@smartsoft001-mobilems/claude-plugins 2.90.0 → 2.91.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smartsoft001-mobilems/claude-plugins",
3
- "version": "2.90.0",
3
+ "version": "2.91.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "mobilems",
3
3
  "description": "MobilEMS-specific Claude Code skills (MuzaCMS / MobileMS indexer API)",
4
- "version": "2.90.0"
4
+ "version": "2.91.0"
5
5
  }
@@ -0,0 +1,84 @@
1
+ ---
2
+ name: mobilems-search
3
+ description: Style and wire the MobilEMS global search results page (`/wyszukaj/:text`) to a museum's approved mockup — the tabbed results view over objects, collections and news, plus the searchbar that feeds it. Use whenever the user wants to build, restyle or fix search, the results tabs, the searchbar, result cards or pagination, or asks to "zrób wyszukiwarkę", "ostyluj wyniki wyszukiwania", "popraw wyszukiwanie globalne", "dodaj zakładkę wyników". The results page ships with the project skeleton, so this skill is about the design, the per-module tabs and the interaction details — not about creating a feature library.
4
+ user-invocable: true
5
+ allowed-tools: Bash, Read, Write, Edit, Glob, Grep, AskUserQuestion
6
+ ---
7
+
8
+ # MobilEMS global search
9
+
10
+ Bring the search results page up to the museum's mockup and make its tabs
11
+ actually work. The page (`apps/web/src/app/pages/search`) and its route come
12
+ with the skeleton; what varies per museum is the styling and which feature
13
+ modules contribute tabs.
14
+
15
+ Search is the page where cross-module wiring goes wrong most often, because a
16
+ tab is owned by the module that renders it while the frame is owned by the app.
17
+ Both sides have to hold up their end.
18
+
19
+ ## Precondition
20
+
21
+ Run `scripts/detect-search.sh <workspace-root>` — confirms the results page and
22
+ the `wyszukaj/:text` route exist. If they do not, the project predates the
23
+ skeleton; build the foundation with `mobilems-project-init` first.
24
+
25
+ ## Framework first — read before writing components
26
+
27
+ 1. `packages/shared/angular/README.md` (installed as
28
+ `node_modules/@smartsoft001-mobilems/angular/README.md`)
29
+ 2. `libs/shared/angular/README.md` — the app's own shared lib
30
+
31
+ | Do not hand-roll | Use |
32
+ | --- | --- |
33
+ | a tab strip | `TabsComponent` / `Tab` from the shared lib (the page already imports it) |
34
+ | result cards | the module's own list-item components (`objects-list-item`, news/collection cards) |
35
+ | "next page" behaviour | the shared `NextPageComponent`, same pattern as the module lists |
36
+ | a search input | `app-objects-searchbar` / the shared searchbar variants |
37
+
38
+ Forking a result card for search is the classic mistake: the card then drifts
39
+ from the module's list and the museum ends up with two visually different
40
+ representations of the same object.
41
+
42
+ ## Steps
43
+
44
+ 1. **Read the mockup** in `docs/mockups/` — the searchbar and the result list
45
+ item are usually exported as separate design-system components rather than a
46
+ full screen, so match the component and keep the page layout consistent with
47
+ the rest of the portal.
48
+ 2. **Tabs come from modules.** Each feature module registers a child route under
49
+ `wyszukaj/:text` (its search module) and the page builds its tab list from
50
+ what is registered. When a tab is missing, fix it in that module's skill
51
+ scope, not by hardcoding the tab here.
52
+ 3. **Direct navigation to a tab must work.** Opening `/wyszukaj/wazy/aktualnosci`
53
+ straight from a link — not by clicking through — has to land on that tab with
54
+ results loaded. This broke repeatedly (MOB-1052…1056) because the active tab
55
+ was derived from click state instead of the URL.
56
+ 4. **Interaction details that the audit checks:** debounce the full-text input
57
+ by 250 ms (`@debounce(250)` from `lodash-decorators`) so every keystroke does
58
+ not hit the API; give the results page its own `title`; keep pagination
59
+ targets at the WCAG 2.5.8 minimum size.
60
+ 5. **Translations.** Labels, tab names, the result counter and the empty state
61
+ all go through translation keys in both `pl` and `en`; run
62
+ `npm run check:translations` (or `npx mobilems-check-translations`).
63
+ The results page invents new keys more often than other pages — it is the one
64
+ place where a phrase like "found N results" has no counterpart elsewhere.
65
+ 6. **Verify** — `scripts/verify-search.sh <workspace-root>`: route, tab wiring,
66
+ debounce, framework components, translation coverage.
67
+
68
+ ## Known pitfalls
69
+
70
+ - **Empty query and no-results states.** Both must render something deliberate;
71
+ a blank page reads as a broken site.
72
+ - **Result counts per tab.** If the mockup shows counts, they have to come from
73
+ the facade's total, not from the length of the loaded page.
74
+ - **Keyboard path.** Type, press Enter, arrow through tabs, reach a result and
75
+ open it — all without a mouse. Search is the most keyboard-driven page in the
76
+ portal.
77
+ - **Phrase in the heading.** Show the searched phrase, escaped — museum
78
+ collections contain quotes and angle brackets in titles.
79
+
80
+ ## Notes
81
+
82
+ - This skill owns the search frame and its styling. A missing or broken tab
83
+ belongs to the feature module that should register it.
84
+ - Bundled `scripts/` ship automatically. Do not hand-edit `plugin.json`.
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # detect-search.sh <workspace-root>
4
+ #
5
+ # Precondition for mobilems-search: the skeleton's results page and route exist.
6
+ set -eu
7
+ ROOT="${1:?usage: detect-search.sh <workspace-root>}"
8
+ cd "$ROOT" 2>/dev/null || { echo "ERROR: no such dir: $ROOT" >&2; exit 2; }
9
+
10
+ miss() { echo "BRAK FUNDAMENTU: $1 — uruchom najpierw /mobilems:project-init" >&2; exit 3; }
11
+
12
+ [ -f apps/web/src/app/pages/search/search.component.ts ] || miss "pages/search/search.component.ts"
13
+ grep -qE "path: *['\"]wyszukaj" apps/web/src/app/app.routes.ts || miss "trasa wyszukaj w app.routes.ts"
14
+ echo "OK: szkielet wyszukiwarki obecny"
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # verify-search.sh <workspace-root>
4
+ #
5
+ # Post-condition for mobilems-search: route + tabs from modules, URL-driven
6
+ # active tab, debounce, framework components, translations. bash 3.2 safe.
7
+ # Env: REF_ROOT=<reference-repo> enables the completeness diff.
8
+ set -eu
9
+ ROOT="${1:?usage: verify-search.sh <workspace-root>}"
10
+ cd "$ROOT" 2>/dev/null || { echo "ERROR: no such dir: $ROOT" >&2; exit 2; }
11
+
12
+ fail=0
13
+ pass() { echo " PASS: $1"; }
14
+ bad() { echo " FAIL: $1" >&2; fail=1; }
15
+
16
+ ROUTES=apps/web/src/app/app.routes.ts
17
+ SEARCH=apps/web/src/app/pages/search
18
+
19
+ echo "== Trasa i zakładki =="
20
+ grep -qE "path: *['\"]wyszukaj" "$ROUTES" && pass "trasa wyszukaj" || bad "brak trasy wyszukaj"
21
+ # Zakładki rejestrują moduły dziedzinowe jako dzieci wyszukaj/:text.
22
+ # Moduły wnoszą zakładki jako *SearchModule — liczymy je bez zgadywania,
23
+ # gdzie dokładnie kończy się blok trasy (formatowanie bywa różne).
24
+ TABS="$(grep -cE "[A-Za-z]+SearchModule" "$ROUTES" || true)"
25
+ [ "${TABS:-0}" -ge 1 ] && pass "moduły rejestrują zakładki wyników ($TABS)" || bad "żaden moduł nie rejestruje zakładki pod wyszukaj/:text"
26
+
27
+ echo "== Aktywna zakładka z URL, nie ze stanu kliknięcia =="
28
+ # Bug MOB-1052…1056: wejście linkiem prosto na zakładkę nie działało.
29
+ if grep -rqE "ActivatedRoute|router\.events|url" "$SEARCH"/search.component.ts 2>/dev/null; then
30
+ pass "komponent czyta zakładkę z routingu"
31
+ else
32
+ bad "zakładka nie jest wyprowadzana z URL — wejście bezpośrednie się zepsuje"
33
+ fi
34
+
35
+ echo "== Komponenty frameworka =="
36
+ grep -rq "TabsComponent" "$SEARCH" 2>/dev/null && pass "zakładki przez TabsComponent" || bad "własny pasek zakładek zamiast TabsComponent"
37
+ FORK="$(grep -rlE "class .*(SearchResultItem|SearchCard)Component" apps/web/src libs 2>/dev/null || true)"
38
+ if [ -n "$FORK" ]; then
39
+ bad "własny kafel wyników zamiast komponentu modułu (rozjedzie się z listą):"
40
+ printf ' %s\n' $FORK >&2
41
+ else
42
+ pass "wyniki renderowane komponentami modułów"
43
+ fi
44
+
45
+ echo "== Interakcja =="
46
+ grep -rq "debounce" apps/web/src libs 2>/dev/null && pass "debounce wyszukiwania obecny" || bad "brak debounce — każde naciśnięcie klawisza uderza w API"
47
+
48
+ echo "== Translacje =="
49
+ if npx --no-install mobilems-check-translations --help >/dev/null 2>&1 || [ -x node_modules/.bin/mobilems-check-translations ]; then
50
+ if npx --no-install mobilems-check-translations ${REF_ROOT:+--reference "$REF_ROOT"}; then
51
+ pass "translacje bez martwych referencji"
52
+ else
53
+ bad "braki w translacjach — popraw wypisane wyżej"
54
+ fi
55
+ else
56
+ echo " SKIP: mobilems-check-translations niedostępny w tym projekcie (starsza linia frameworka)"
57
+ fi
58
+
59
+ echo
60
+ if [ "$fail" = 0 ]; then echo "VERIFY: all checks passed."; else echo "VERIFY: FAILED — fix the items above and re-run." >&2; fi
61
+ exit "$fail"
@@ -0,0 +1,81 @@
1
+ ---
2
+ name: mobilems-static-pages
3
+ description: Style and wire the MobilEMS static CMS pages (`/strona/:id`, `/strona/:id/:slug`, `/kontakt`) to a museum's approved mockup — the About / Accessibility statement / Privacy policy / Contact pages every portal has. Use whenever the user wants to build, restyle or fix the static pages, the CMS page template, the contact page, or asks to "zrób strony statyczne", "podłącz strony z CMS", "ostyluj stronę Kontakt", "strony O nas / deklaracja dostępności / polityka prywatności". The page scaffolding ships with the project skeleton, so this skill is about making it match the design and render real CMS content — not about creating a feature library.
4
+ user-invocable: true
5
+ allowed-tools: Bash, Read, Write, Edit, Glob, Grep, AskUserQuestion
6
+ ---
7
+
8
+ # MobilEMS static pages
9
+
10
+ Bring the museum's static pages up to its approved mockup. Unlike the feature
11
+ modules, there is nothing to scaffold: `apps/web/src/app/pages/page` (CMS page
12
+ template + resolver) and `pages/contact` come with the skeleton, and their
13
+ routes are already registered. What differs per museum is the design and the
14
+ CMS wiring — which is exactly what tends to be missing when these pages are
15
+ built ad hoc.
16
+
17
+ ## Precondition
18
+
19
+ Run `scripts/detect-pages.sh <workspace-root>`. It confirms the skeleton pages
20
+ and their routes exist. If they do not, the project predates the skeleton that
21
+ ships them — build them from `mobilems-project-init` first rather than
22
+ hand-rolling here, so every museum keeps the same structure.
23
+
24
+ ## Framework first — read before writing components
25
+
26
+ Static pages are mostly composition, so almost everything you need already
27
+ exists. Re-implementing it is a defect, not a shortcut:
28
+
29
+ 1. `packages/shared/angular/README.md` (installed as
30
+ `node_modules/@smartsoft001-mobilems/angular/README.md`) — the framework API catalog
31
+ 2. `libs/shared/angular/README.md` — the app's own shared lib
32
+
33
+ | Do not hand-roll | Use |
34
+ | --- | --- |
35
+ | a rich-text renderer for CMS body HTML | the page template's existing content block + widget map |
36
+ | per-page galleries / sliders | the widget content-type components (`WIDGET` group) |
37
+ | menu and footer links | the API menu configuration (see pitfalls — hardcoding them was a reported bug) |
38
+ | meta/OG tags | `SeoService` / `MetaService` |
39
+
40
+ ## Steps
41
+
42
+ 1. **Read the mockup.** Exports live in `docs/mockups/`; read them (Read) rather
43
+ than guessing from the Figma link. Note the container width, heading scale,
44
+ spacing rhythm and how the page header/hero differs from the module pages.
45
+ 2. **CMS data — render everything the API sends.** The page payload carries more
46
+ than a title and body: `image`, `backgroundImage`, `links`, `slides`.
47
+ A field that arrives and is not rendered reads to the client as a missing
48
+ feature, so walk the resolver's payload and account for each field.
49
+ 3. **Contact page.** The contact page's CMS id is per-instance, so the `kontakt`
50
+ route resolves it through the menu rather than a constant. Keep it that way —
51
+ a hardcoded id works on one museum and breaks on the next.
52
+ 4. **Translations.** Every static label goes through a key in the `CONTACT`
53
+ group (plus `COMMON` where it is genuinely shared); no Polish literals in
54
+ templates, and both `pl` and `en` filled. Run `npm run check:translations`
55
+ (or `npx mobilems-check-translations`) — a raw `CONTACT.something` on screen
56
+ is one of the most visible defects a user can hit.
57
+ 5. **Verify** — `scripts/verify-pages.sh <workspace-root>`: asserts the routes,
58
+ the resolver wiring, translation coverage and that no menu/footer link is
59
+ hardcoded. Fix and re-run.
60
+
61
+ ## Known pitfalls (fix while styling, not after)
62
+
63
+ - **Hardcoded navigation.** Footer and menu entries come from the API config.
64
+ Two separate bugs (MOB-1044, MOB-1071) traced back to links pasted into
65
+ templates — they render fine on the museum you are looking at and 404 on the
66
+ next one.
67
+ - **One `h1` per page.** The CMS title is the `h1`; a second one in the hero or
68
+ breadcrumb is a WCAG 1.3.1 violation that the audit will catch.
69
+ - **360 px without horizontal scroll.** Long CMS words and wide embedded media
70
+ are the usual culprits; test the narrow viewport before calling it done.
71
+ - **Dark / high-contrast mode.** The page renders client HTML, so contrast
72
+ overrides must reach nested CMS markup (`[&_p]`, `[&_a]`, headings) — checking
73
+ only the page chrome misses the body text.
74
+ - **Empty states.** A CMS page with no body, no image or no links must still
75
+ render a sane layout; museums publish half-filled pages more often than not.
76
+
77
+ ## Notes
78
+
79
+ - This skill touches the static pages only. Feature modules (objects,
80
+ collections, news) have their own skills and their own libraries.
81
+ - Bundled `scripts/` ship automatically. Do not hand-edit `plugin.json`.
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # detect-pages.sh <workspace-root>
4
+ #
5
+ # Precondition for mobilems-static-pages: the skeleton's static pages and their
6
+ # routes exist. bash 3.2 safe.
7
+ set -eu
8
+ ROOT="${1:?usage: detect-pages.sh <workspace-root>}"
9
+ cd "$ROOT" 2>/dev/null || { echo "ERROR: no such dir: $ROOT" >&2; exit 2; }
10
+
11
+ miss() { echo "BRAK FUNDAMENTU: $1 — uruchom najpierw /mobilems:project-init" >&2; exit 3; }
12
+
13
+ [ -f apps/web/src/app/pages/page/page.component.ts ] || miss "pages/page/page.component.ts"
14
+ [ -f apps/web/src/app/pages/page/page.resolver.ts ] || miss "pages/page/page.resolver.ts"
15
+ grep -q "strona/:id" apps/web/src/app/app.routes.ts || miss "trasa strona/:id w app.routes.ts"
16
+ echo "OK: szkielet stron statycznych obecny"
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # verify-pages.sh <workspace-root>
4
+ #
5
+ # Post-condition for mobilems-static-pages: routes wired, CMS payload rendered,
6
+ # navigation not hardcoded, translations complete. bash 3.2 safe.
7
+ # Env: REF_ROOT=<reference-repo> enables the completeness diff.
8
+ set -eu
9
+ ROOT="${1:?usage: verify-pages.sh <workspace-root>}"
10
+ cd "$ROOT" 2>/dev/null || { echo "ERROR: no such dir: $ROOT" >&2; exit 2; }
11
+
12
+ fail=0
13
+ pass() { echo " PASS: $1"; }
14
+ bad() { echo " FAIL: $1" >&2; fail=1; }
15
+
16
+ ROUTES=apps/web/src/app/app.routes.ts
17
+ PAGE=apps/web/src/app/pages/page
18
+
19
+ echo "== Trasy =="
20
+ grep -q "strona/:id" "$ROUTES" && pass "trasa strona/:id" || bad "brak trasy strona/:id"
21
+ grep -q "strona/:id/:slug" "$ROUTES" && pass "trasa strona/:id/:slug (SEO slug)" || bad "brak trasy ze slugiem"
22
+ grep -qE "path: *'kontakt'" "$ROUTES" && pass "trasa kontakt" || bad "brak trasy kontakt"
23
+ grep -q "pageResolver" "$ROUTES" && pass "resolver podpięty do trasy" || bad "trasa bez pageResolver"
24
+
25
+ echo "== Treść z CMS =="
26
+ # Pola, których pominięcie klient odbiera jako brak funkcji.
27
+ for field in image links; do
28
+ grep -rq "$field" "$PAGE" 2>/dev/null && pass "szablon używa pola $field" || bad "pole $field z CMS nigdzie nierenderowane"
29
+ done
30
+
31
+ echo "== Nawigacja z konfiguracji, nie z kodu =="
32
+ # Twarde ścieżki do stron CMS w szablonach = bug MOB-1044/MOB-1071.
33
+ HARD="$(grep -rlE "routerLink=\"/strona/[0-9]" apps/web/src libs 2>/dev/null || true)"
34
+ if [ -n "$HARD" ]; then
35
+ bad "twarde linki do stron CMS (id jest per-instancja):"
36
+ printf ' %s\n' $HARD >&2
37
+ else
38
+ pass "brak twardych linków do stron CMS"
39
+ fi
40
+
41
+ echo "== Dostępność =="
42
+ H1="$(grep -rc "<h1" "$PAGE"/*.html 2>/dev/null | awk -F: '{s+=$2} END {print s+0}')"
43
+ [ "${H1:-0}" -le 1 ] && pass "co najwyżej jeden h1 w szablonie strony" || bad "kilka h1 w szablonie strony ($H1) — WCAG 1.3.1"
44
+
45
+ echo "== Translacje =="
46
+ if npx --no-install mobilems-check-translations --help >/dev/null 2>&1 || [ -x node_modules/.bin/mobilems-check-translations ]; then
47
+ if npx --no-install mobilems-check-translations --groups "CONTACT" ${REF_ROOT:+--reference "$REF_ROOT"}; then
48
+ pass "grupa CONTACT kompletna"
49
+ else
50
+ bad "braki w translacjach — popraw wypisane wyżej"
51
+ fi
52
+ else
53
+ echo " SKIP: mobilems-check-translations niedostępny w tym projekcie (starsza linia frameworka)"
54
+ fi
55
+
56
+ echo
57
+ if [ "$fail" = 0 ]; then echo "VERIFY: all checks passed."; else echo "VERIFY: FAILED — fix the items above and re-run." >&2; fi
58
+ exit "$fail"