@smartsoft001-mobilems/claude-plugins 2.88.0 → 2.90.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/README.md +27 -2
- package/package.json +1 -1
- package/plugins/mobilems/.claude-plugin/README.md +21 -2
- package/plugins/mobilems/.claude-plugin/plugin.json +1 -1
- package/plugins/mobilems/skills/mobilems-articles/SKILL.md +52 -20
- package/plugins/mobilems/skills/mobilems-articles/references/module-and-routes.md +24 -0
- package/plugins/mobilems/skills/mobilems-articles/scripts/check-translations.js +90 -0
- package/plugins/mobilems/skills/mobilems-articles/scripts/verify-module.sh +53 -0
- package/plugins/mobilems/skills/mobilems-devops-config/SKILL.md +141 -0
- package/plugins/mobilems/skills/mobilems-devops-config/references/docker.md +58 -0
- package/plugins/mobilems/skills/mobilems-devops-config/references/env-and-lint.md +59 -0
- package/plugins/mobilems/skills/mobilems-devops-config/references/github-hygiene.md +54 -0
- package/plugins/mobilems/skills/mobilems-devops-config/references/tooling.md +105 -0
- package/plugins/mobilems/skills/mobilems-devops-config/references/workflows.md +410 -0
- package/plugins/mobilems/skills/mobilems-devops-config/scripts/detect-foundation.sh +47 -0
- package/plugins/mobilems/skills/mobilems-devops-config/scripts/verify-devops.sh +96 -0
- package/plugins/mobilems/skills/mobilems-events/SKILL.md +27 -1
- package/plugins/mobilems/skills/mobilems-events/references/module-and-routes.md +24 -0
- package/plugins/mobilems/skills/mobilems-events/scripts/verify-module.sh +43 -0
- package/plugins/mobilems/skills/mobilems-object-collections/SKILL.md +46 -14
- package/plugins/mobilems/skills/mobilems-object-collections/references/lib-contents.md +11 -0
- package/plugins/mobilems/skills/mobilems-object-collections/references/module-and-routes.md +26 -0
- package/plugins/mobilems/skills/mobilems-object-collections/scripts/check-translations.js +90 -0
- package/plugins/mobilems/skills/mobilems-object-collections/scripts/verify-module.sh +54 -0
- package/plugins/mobilems/skills/mobilems-objects/SKILL.md +42 -10
- package/plugins/mobilems/skills/mobilems-objects/references/module-and-routes.md +24 -0
- package/plugins/mobilems/skills/mobilems-objects/scripts/check-translations.js +90 -0
- package/plugins/mobilems/skills/mobilems-objects/scripts/verify-module.sh +53 -0
- package/plugins/mobilems/skills/mobilems-partners/SKILL.md +30 -2
- package/plugins/mobilems/skills/mobilems-partners/references/module-and-routes.md +24 -0
- package/plugins/mobilems/skills/mobilems-partners/scripts/check-translations.js +90 -0
- package/plugins/mobilems/skills/mobilems-partners/scripts/verify-module.sh +53 -0
- package/plugins/mobilems/skills/mobilems-project-init/SKILL.md +68 -8
- package/plugins/mobilems/skills/mobilems-project-init/references/branding-reset.md +112 -0
- package/plugins/mobilems/skills/mobilems-project-init/references/claude-config.md +7 -0
- package/plugins/mobilems/skills/mobilems-project-init/references/config-providers.md +1 -1
- package/plugins/mobilems/skills/mobilems-project-init/references/qa-hardening.md +30 -30
- package/plugins/mobilems/skills/mobilems-project-init/references/shared-lib.md +42 -5
- package/plugins/mobilems/skills/mobilems-project-init/references/tailwind-styles.md +33 -23
- package/plugins/mobilems/skills/mobilems-project-init/scripts/verify-init.sh +62 -9
- package/plugins/mobilems/skills/mobilems-thematic-publications/SKILL.md +25 -1
- package/plugins/mobilems/skills/mobilems-thematic-publications/references/lib-contents.md +11 -0
- package/plugins/mobilems/skills/mobilems-thematic-publications/references/module-and-routes.md +26 -0
- package/plugins/mobilems/skills/mobilems-thematic-publications/scripts/verify-module.sh +43 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Branding + SEO reset — strip the reference museum's identity
|
|
2
|
+
|
|
3
|
+
Reference mode copies a **different museum's** app. Its brand and SEO travel with the code and are
|
|
4
|
+
invisible until QA (or the client) finds them: fonts named after the old project, its palette, its
|
|
5
|
+
logo, its domain in `og:url`, its name in `<title>` and in the PL/EN translation strings.
|
|
6
|
+
|
|
7
|
+
Run this **after** the shared lib + app shell are copied (steps 7–8) and **before** QA hardening.
|
|
8
|
+
It is a **token/content** change only.
|
|
9
|
+
|
|
10
|
+
## The invariant — re-skin, never re-build
|
|
11
|
+
|
|
12
|
+
Allowed to change: colour/font/spacing **token values**, asset **files**, text **content**, site
|
|
13
|
+
identity (name, domain, social image).
|
|
14
|
+
|
|
15
|
+
Never change as part of this step:
|
|
16
|
+
|
|
17
|
+
- layout or utility classes in templates (`smart-*`), DOM structure, component inputs/outputs
|
|
18
|
+
- API field mapping, `baseQuery`/`query` keys, dictionary keys (lowercase — a rename breaks filters
|
|
19
|
+
with HTTP 409), route paths and slugs
|
|
20
|
+
- translation **keys** (only their values), NgRx state shape, service contracts
|
|
21
|
+
|
|
22
|
+
If a colour/font swap seems to require a template change, it is a design change — raise it with the
|
|
23
|
+
user instead of doing it silently.
|
|
24
|
+
|
|
25
|
+
## 1. Decide the mode (ask once, `AskUserQuestion`)
|
|
26
|
+
|
|
27
|
+
- **Brand spec mode** — the user supplies fonts, palette, logo, social image, site name/domain.
|
|
28
|
+
Apply it, and still run every check below.
|
|
29
|
+
- **Neutral mode (default)** — apply the generic token set in §2. The result is a deliberately plain
|
|
30
|
+
but complete, WCAG-clean skin the client's designer can replace later.
|
|
31
|
+
|
|
32
|
+
## 2. Neutral token set (the default)
|
|
33
|
+
|
|
34
|
+
| Token | Value |
|
|
35
|
+
| -------------------- | --------------------------------------------------------------------------- |
|
|
36
|
+
| Heading font | **Playfair Display** (full latin-ext — covers `ą ć ę ł ń ś ź ż`) |
|
|
37
|
+
| Body / UI font | **Inter** (fallback `system-ui, sans-serif`) |
|
|
38
|
+
| Text on white | `#1f2937` (≈ 15:1), secondary `#4b5563` (≈ 7.6:1) — never `#9ca3af` (2.5:1) |
|
|
39
|
+
| Surfaces | `#ffffff` page, `#f4f4f5` muted, `#e4e4e7` border |
|
|
40
|
+
| Accent / primary | `#3f5b76` with white text (≈ 5.6:1); active `#334a61` |
|
|
41
|
+
| High-contrast (WCAG) | bg `#1d1d1d`, text `#ffed00`, links `#86d7be` (keep the framework's values) |
|
|
42
|
+
| Logo / `no-image` | Neutral placeholder SVG carrying the app name, no reference museum mark |
|
|
43
|
+
| Social image | Locally generated `gfx/social-logo.jpg` 1200×550 with the app name |
|
|
44
|
+
|
|
45
|
+
Every generated text/background pair must be checked ≥4.5:1 before moving on.
|
|
46
|
+
|
|
47
|
+
## 3. Carriers to reset — checklist
|
|
48
|
+
|
|
49
|
+
**Styles**
|
|
50
|
+
|
|
51
|
+
- `tailwind.config.js` — `theme.extend.colors.*` and `fontFamily.*`. Step 4 already wrote the neutral
|
|
52
|
+
values under role-based keys (`heading`, `body`, `ui`); in brand-spec mode swap the **values**, never
|
|
53
|
+
the keys. Delete any font token named after a typeface or another project that a copied file
|
|
54
|
+
re-added. If copied templates still use such class names, remap those classes onto the role tokens
|
|
55
|
+
or keep one clearly labelled remap block — never leave an unexplained legacy name. No `fontFamily`
|
|
56
|
+
entry may be `[]`.
|
|
57
|
+
- `apps/web/src/styles.scss` — the typography header block, `@font-face` families and the metric
|
|
58
|
+
fallbacks (`* Fallback` / `* Fallback Android`) must name the new fonts; drop rules that target the
|
|
59
|
+
reference museum's own selectors.
|
|
60
|
+
- Any hardcoded hex in copied shared components that duplicates a palette token → replace with the
|
|
61
|
+
token (do not restyle the component).
|
|
62
|
+
|
|
63
|
+
**Assets** (`apps/web/public/gfx`, `apps/web/public`)
|
|
64
|
+
|
|
65
|
+
- logo(s) (`main-logo`, footer/white variants), `no-image` placeholder, `social-logo.jpg`,
|
|
66
|
+
`favicon.ico` + 32×32 + 192×192 + `apple-touch-icon`, `manifest.webmanifest` name/icons.
|
|
67
|
+
- Delete reference-only assets (partner/funding logos of the other museum, its banners). Serve each
|
|
68
|
+
image near its rendered size (oversized copies trigger `NG0913`).
|
|
69
|
+
|
|
70
|
+
**SEO / identity**
|
|
71
|
+
|
|
72
|
+
- `apps/web/src/index.html` — `<title>`, `description`, `og:title`/`og:description`/`og:url`/
|
|
73
|
+
`og:image`(+`:secure_url`,`:width`,`:height`,`:alt`), `twitter:*`. Absolute URLs come from the new
|
|
74
|
+
`SITE_URL`.
|
|
75
|
+
- `museum-seo.service.ts` — default OG image, base title, locale map; no reference host anywhere.
|
|
76
|
+
- `sitemap.xml` / `robots.txt` — dynamic `SITE_URL`-driven endpoints only (see `qa-hardening.md` §2).
|
|
77
|
+
- `environment.ts` / `.prod.ts` / `.env.dev` — `apiUrl`, `multimediaUrl`, `siteUrl` of THIS museum.
|
|
78
|
+
|
|
79
|
+
**Content**
|
|
80
|
+
|
|
81
|
+
- `apps/web/public/translations.json` — museum name, base title (`MODEL.mainTitle`), skip-link
|
|
82
|
+
labels, footer/contact copy, static-page fallbacks — **both** PL and EN. Keys unchanged.
|
|
83
|
+
- Footer/contact templates: no hardcoded reference address, phone, e-mail or socials (live data comes
|
|
84
|
+
from the CMS API).
|
|
85
|
+
- Comments that name the origin project — rewrite or drop.
|
|
86
|
+
|
|
87
|
+
## 4. Prove it — no leftovers
|
|
88
|
+
|
|
89
|
+
Grep the workspace for the reference project's identity and fix every hit (case-insensitive; use the
|
|
90
|
+
reference repo's own name, museum name and domain, plus its import prefix):
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
grep -rniE "<source-project-name>|<source-domain>|@<source-prefix>/" \
|
|
94
|
+
apps libs *.js *.json --include="*.ts" --include="*.html" --include="*.scss" \
|
|
95
|
+
--include="*.json" --include="*.js" | grep -v node_modules
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Expected result: **no hits**.
|
|
99
|
+
|
|
100
|
+
`verify-init.sh` independently asserts a narrower set: font tokens are role-named (`heading` / `body`
|
|
101
|
+
/ `ui`, not named after a typeface or a project), no `{{...}}` placeholder survives, no workspace
|
|
102
|
+
alias other than `@<PREFIX>/` is mapped, `fontFamily` has no empty entry, and a favicon exists.
|
|
103
|
+
|
|
104
|
+
It hardcodes **no** project identity. In reference mode, pass the source project's slug or domain as
|
|
105
|
+
its third argument and it will grep for that too:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
scripts/verify-init.sh <workspace-root> <PREFIX> <source-project-slug>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
That narrower set is not a substitute for the sweep above — it does not look at logos, `og:`/
|
|
112
|
+
`twitter:` tags, the manifest, or contrast ratios. Run the full sweep yourself and report it.
|
|
@@ -29,6 +29,13 @@ permission / MCP allow-lists. **Extend, do not replace** the base file — keep
|
|
|
29
29
|
> hosts (its own portal domain, project n8n/maia webhooks). Seed the generic-useful entries and let
|
|
30
30
|
> the project grow its own.
|
|
31
31
|
|
|
32
|
+
## Agent config lives in `.claude/`, never `.github/`
|
|
33
|
+
|
|
34
|
+
The Nx scaffolding may have written `.github/skills/`, `.github/agents/`, `.github/prompts/` (the
|
|
35
|
+
Copilot layout). Those duplicate the enabled `nx@nx-claude-plugins` plugin. `mobilems-devops-config`
|
|
36
|
+
owns that cleanup (`references/github-hygiene.md`) — if you see them here, either run that skill or
|
|
37
|
+
apply the same rule: delete plugin duplicates, `git mv` bespoke ones into `.claude/`.
|
|
38
|
+
|
|
32
39
|
## tools/specs + tools/prompts
|
|
33
40
|
|
|
34
41
|
Seed pointers so the museum conventions are discoverable (the framework repo keeps the canonical
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# app.config.ts — the MobilEMS provider set
|
|
2
2
|
|
|
3
3
|
Overwrite `apps/web/src/app/app.config.ts` with the providers below (the base shipped a minimal
|
|
4
|
-
version). Thread `<PREFIX
|
|
4
|
+
version). Thread `<PREFIX>`. `app.config.server.ts` and
|
|
5
5
|
`app.routes.server.ts` stay as the base emitted them.
|
|
6
6
|
|
|
7
7
|
The imports from `@<PREFIX>/angular` (`LanguageInterceptor`, `PreviewAuthInterceptor`,
|
|
@@ -1,26 +1,27 @@
|
|
|
1
|
-
# QA hardening
|
|
1
|
+
# QA hardening
|
|
2
2
|
|
|
3
|
-
Every item below is a
|
|
4
|
-
|
|
5
|
-
a reference repo, so the default failure mode is **reference-project leftovers** plus a handful of
|
|
3
|
+
Every item below is a defect class that recurs on museum projects. The foundation is copied from a
|
|
4
|
+
reference repo, so the default failure mode is **source-project leftovers** plus a handful of
|
|
6
5
|
recurring SEO/i18n/WCAG gaps. Work through this checklist when applying the delta — each item is
|
|
7
|
-
cheap to do during init and expensive to chase later
|
|
6
|
+
cheap to do during init and expensive to chase later.
|
|
8
7
|
|
|
9
8
|
## 1. No reference-project leftovers (branding)
|
|
10
9
|
|
|
11
10
|
The reference repo belongs to a _different museum_. Everything carrying that museum's identity must
|
|
12
|
-
be replaced or generated for the target project
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
be replaced or generated for the target project. **`references/branding-reset.md` (step 9) is the
|
|
12
|
+
full checklist — styles, fonts, palette, assets, translations — and runs before this one.** What
|
|
13
|
+
follows are the SEO-side items:
|
|
14
|
+
|
|
15
|
+
- **`sitemap.xml` + `robots.txt`** — never ship static files; a static copy hardcodes whatever
|
|
16
|
+
domain it was written with. Implement them as **dynamic SSR endpoints** driven by the `SITE_URL`
|
|
17
|
+
env var — see section 2.
|
|
18
|
+
- **`og:image` / `og:image:secure_url` / `twitter:image` / `og:url`** — must point at this app's own
|
|
19
|
+
domain. Build absolute URLs from `SITE_URL`/`siteUrl`; ship a local `gfx/social-logo.jpg` for this
|
|
20
|
+
app rather than pointing at another deploy.
|
|
20
21
|
- **Favicon** — the base often has none. Ship the full set: `favicon.ico`, 32×32 + 192×192 PNG,
|
|
21
|
-
`apple-touch-icon
|
|
22
|
+
`apple-touch-icon`.
|
|
22
23
|
- **Skip links** — keep them (they are required), but rewrite their labels/targets for THIS app's
|
|
23
|
-
sections; copied skip
|
|
24
|
+
sections; a copied skip link still names the source project. Localize them (PL/EN translation keys).
|
|
24
25
|
- **Footer / contact data** — target museum's phone, e-mail, socials; links come from the CMS API,
|
|
25
26
|
not hardcode.
|
|
26
27
|
- Local static assets (funding logos etc.) must be served near their rendered size — oversized
|
|
@@ -28,7 +29,7 @@ be replaced or generated for the target project:
|
|
|
28
29
|
|
|
29
30
|
## 2. Dynamic sitemap + robots endpoints (server.ts)
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
Put the logic in **pure, testable functions** in
|
|
32
33
|
`apps/web/src/seo/seo-endpoints.ts` (`resolveSiteUrl`, `buildSitemapXml`, `buildRobotsTxt`), and
|
|
33
34
|
wire thin routes in `server.ts`:
|
|
34
35
|
|
|
@@ -47,7 +48,7 @@ wire thin routes in `server.ts`:
|
|
|
47
48
|
|
|
48
49
|
- `<meta name="description">` + complete OpenGraph (`og:title`, `og:description`, `og:image`,
|
|
49
50
|
`og:url`) + Twitter Card on the home page, in **both** languages, re-set on language switch.
|
|
50
|
-
- `og:locale` must follow the active language
|
|
51
|
+
- `og:locale` must follow the active language; never hardcode `pl_PL`. In
|
|
51
52
|
`museum-seo.service.ts` use a locale map (`pl → pl_PL`, `en → en_GB`) read from
|
|
52
53
|
`translateService.currentLang` (fallback via `defaultLang` — `currentLang` can be `undefined`
|
|
53
54
|
during SSR), and emit one `og:locale:alternate`.
|
|
@@ -67,22 +68,21 @@ wire thin routes in `server.ts`:
|
|
|
67
68
|
|
|
68
69
|
## 5. WCAG invariants
|
|
69
70
|
|
|
70
|
-
- **Contrast:**
|
|
71
|
-
|
|
71
|
+
- **Contrast:** light greys fail AA on white — `#9ca3af` is only 2.53:1. Use ≥4.5:1 for text:
|
|
72
|
+
`#6f6f6f` ≈ 5.0:1, `#4b5563` ≈ 7.6:1.
|
|
72
73
|
Figma mockups themselves sometimes specify failing colours — match the design _intent_ with the
|
|
73
74
|
nearest compliant shade instead of copying the hex blindly, and note the deviation.
|
|
74
|
-
- **Headings:** exactly one `h1` per page; no skipped levels (an `h1 → h3` jump
|
|
75
|
-
|
|
76
|
-
- **alt text:** when the alt comes from a CMS title, strip HTML first (`smartRemoveHtml`)
|
|
77
|
-
|
|
75
|
+
- **Headings:** exactly one `h1` per page; no skipped levels (an `h1 → h3` jump is an axe-core
|
|
76
|
+
finding). Detail pages get an `h1` (the item title), image captions are NOT headings.
|
|
77
|
+
- **alt text:** when the alt comes from a CMS title, strip HTML first (`smartRemoveHtml`),
|
|
78
|
+
otherwise the alt reads `<p>Tytuł</p>`.
|
|
78
79
|
- **Keyboard:** any card implemented as `role="link"`/`tabindex=0` must activate on Enter/Space
|
|
79
80
|
(or better, be a real `<a href>`). Focus must be visible; labels should react to focus/hover the
|
|
80
81
|
same way the rest of the card content does.
|
|
81
|
-
- **Fonts must cover Polish diacritics.**
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
to system sans.
|
|
82
|
+
- **Fonts must cover Polish diacritics.** Decorative serifs frequently lack `ą ć ę ł ń ś ź ż`
|
|
83
|
+
(+ uppercase), so titles render in a silent fallback. Check glyph coverage before adopting a face;
|
|
84
|
+
**Playfair Display** and **Gilda Display** are full-latin-ext. Never leave a `tailwind.config.js`
|
|
85
|
+
`fontFamily` entry as an empty array — it silently falls back to system sans.
|
|
86
86
|
|
|
87
87
|
## 6. Console hygiene (build + runtime must be warning-clean)
|
|
88
88
|
|
|
@@ -107,11 +107,11 @@ These conventions were enforced by QA across modules — bake them in from the s
|
|
|
107
107
|
|
|
108
108
|
- **One card component per entity, reused everywhere.** The home page, module lists and search
|
|
109
109
|
results must render the same shared `*-grid-item` / `*-list-item` components — a second ad-hoc
|
|
110
|
-
card implementation on the home page
|
|
110
|
+
card implementation on the home page is a defect, not a variant.
|
|
111
111
|
- **Full-text search inputs debounce 250 ms** (`@debounce(250)` from `lodash-decorators`) — in every
|
|
112
112
|
module's filters (objects, collections, articles/news).
|
|
113
113
|
- **Every list page shows the total result count** (`facade.totalCount()`), independent of
|
|
114
|
-
pagination
|
|
114
|
+
pagination.
|
|
115
115
|
- **"Next page" button** at the bottom of each list follows one shared pattern
|
|
116
116
|
(`NextPageComponent`: `selectedPage`/`lastPageIndex` from `totalCount()` + limit, scroll-to-top on
|
|
117
117
|
advance, hidden on the last page).
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
# Build the foundation shared library
|
|
2
2
|
|
|
3
3
|
The shared library `libs/shared/angular` (alias `@<PREFIX>/angular`) holds the museum's shared
|
|
4
|
-
Angular building blocks: the `App` shell, header, footer, the generic page renderer,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
`libs/shared/angular/src/lib` and threading `<PREFIX>`
|
|
4
|
+
Angular building blocks: the `App` shell, header, footer, the generic page renderer, gallery, map,
|
|
5
|
+
slider, carousels, content widgets, WCAG + SEO services, interceptors, pipes, directives, tools,
|
|
6
|
+
models, and `configs.module.ts`. Build it by copying from the reference repo's
|
|
7
|
+
`libs/shared/angular/src/lib` and threading `<PREFIX>` in place of that repo's own alias.
|
|
8
|
+
|
|
9
|
+
Filter components are **not** on that list. Each module builds its own by extending the framework's
|
|
10
|
+
`FiltersBaseComponent<T>` (see `SKILL.md` → "Framework first"); the shared lib holds no filter
|
|
11
|
+
implementation to copy.
|
|
8
12
|
|
|
9
13
|
The library starts as the base shell that exports only `environment` + `EnvironmentService` with
|
|
10
14
|
empty `lib/` placeholder dirs — fill those dirs with the **foundation shared components**.
|
|
@@ -86,6 +90,29 @@ see `server-env.md`), and `configs.module.ts`. These are foundation code. Confir
|
|
|
86
90
|
build-safety grep below; if any of these files imports a feature package on your reference, it is
|
|
87
91
|
feature code and belongs to a module skill — leave it out.
|
|
88
92
|
|
|
93
|
+
**Build each of these ONCE here — module skills reuse them and must never re-create a local copy.**
|
|
94
|
+
Check the framework catalog (`node_modules/@smartsoft001-mobilems/angular/README.md`, in-repo
|
|
95
|
+
[`packages/shared/angular/README.md`](https://github.com/smartsoft001/mobilems-framework/blob/main/packages/shared/angular/README.md))
|
|
96
|
+
first: if the framework already exports it — `MasonryGridComponent` and `FiltersBaseComponent` /
|
|
97
|
+
`FiltersContext` above all, plus `FileUrlService`, `SeoService`, `MetaService`, `DictionaryService`,
|
|
98
|
+
`SearchService`, `WcagService`, `ContrastService`, `StyleService`, `ModalService`,
|
|
99
|
+
`ClickOutsideDirective`, `HoverDirective`, `ScrollableDirective`, … — import it instead of copying
|
|
100
|
+
the reference's version. The reference repo predates parts of the framework, so several of its shared
|
|
101
|
+
components duplicate exports that now exist; copying those is the single most common defect in this
|
|
102
|
+
step. The app-level set the framework does **not** provide, and that the module skills expect to find
|
|
103
|
+
here:
|
|
104
|
+
|
|
105
|
+
| Kind | Expected members |
|
|
106
|
+
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------- |
|
|
107
|
+
| pipes | `altText`, `capitalize`, `fileUrl`, `truncateHtml` |
|
|
108
|
+
| tools | `isInternalLink`, `normalizeUrl`, `stripHtml` (+ the shared `tools.ts` helpers) |
|
|
109
|
+
| directives | `externalLink` |
|
|
110
|
+
| interceptors | `language`, `preview-auth`, `ssr-timeout` |
|
|
111
|
+
| services | `museum-seo`, `filter-persistence`, `local-storage`, `orientation`, `confirmation-modal`, `contact`, `data`, `environment`, `wcag` |
|
|
112
|
+
|
|
113
|
+
Adjust to what the reference actually ships, but keep the rule: one implementation, in this lib,
|
|
114
|
+
exported from the barrel, documented in the app's own README so the module skills can find it.
|
|
115
|
+
|
|
89
116
|
## Barrels
|
|
90
117
|
|
|
91
118
|
- `src/index.ts` — the full barrel: re-export `./lib/components`, `./lib/services`,
|
|
@@ -95,6 +122,16 @@ feature code and belongs to a module skill — leave it out.
|
|
|
95
122
|
which holds `AppComponent`/`FooterComponent`/`HeaderComponent`). Module skills add their feature
|
|
96
123
|
shared components' exports when they build them.
|
|
97
124
|
|
|
125
|
+
## `libs/shared/angular/README.md` — required
|
|
126
|
+
|
|
127
|
+
Write a README for the lib listing what it exports, in the same shape as the framework catalog:
|
|
128
|
+
components, services, pipes, tools, directives, interceptors, models — one line each, saying what it
|
|
129
|
+
is for. This is not decoration: the module skills read it to decide what to reuse, and it is the only
|
|
130
|
+
place the app-level (non-framework) helpers are discoverable. Head it with a pointer to the framework
|
|
131
|
+
catalog (`node_modules/@smartsoft001-mobilems/angular/README.md`) and the rule "framework first, then
|
|
132
|
+
this lib, then — only if neither has it — new code". Update it whenever a module skill adds a shared
|
|
133
|
+
component.
|
|
134
|
+
|
|
98
135
|
## Build-safety invariant
|
|
99
136
|
|
|
100
137
|
The foundation library must build with no feature package installed. The check is positive and
|
|
@@ -122,4 +159,4 @@ copy those from the reference and normalize their `dest`/`coverageDirectory`/pat
|
|
|
122
159
|
After copying, the only reference-prefix string left should be gone. Beyond the import statements,
|
|
123
160
|
remember to thread `<PREFIX>` in `libs/shared/angular/package.json` `"name"` (it reads
|
|
124
161
|
`@<reference-prefix>/angular` in the reference → set it to `@<PREFIX>/angular`). A workspace-wide grep
|
|
125
|
-
for the
|
|
162
|
+
for the source repo's own prefix should return nothing.
|
|
@@ -6,6 +6,10 @@ postcss, so scss and Tailwind coexist — no migration.
|
|
|
6
6
|
|
|
7
7
|
## 1. `tailwind.config.js` (workspace root — create verbatim, no placeholders)
|
|
8
8
|
|
|
9
|
+
The token **values** below are the neutral default set (`references/branding-reset.md` §2) — a plain,
|
|
10
|
+
WCAG-clean skin. The token **keys** are the structural contract the templates use; keep them exactly
|
|
11
|
+
as written. Step 9 swaps the values for the client's brand spec if there is one.
|
|
12
|
+
|
|
9
13
|
```js
|
|
10
14
|
/** @type {import('tailwindcss').Config} */
|
|
11
15
|
module.exports = {
|
|
@@ -16,13 +20,14 @@ module.exports = {
|
|
|
16
20
|
extend: {
|
|
17
21
|
colors: {
|
|
18
22
|
primary: {
|
|
19
|
-
DEFAULT: '#
|
|
20
|
-
active: '
|
|
21
|
-
|
|
23
|
+
DEFAULT: '#1f2937',
|
|
24
|
+
active: '#e4e4e7',
|
|
25
|
+
accent: '#3f5b76',
|
|
26
|
+
red: '#b3261e',
|
|
22
27
|
},
|
|
23
28
|
dark: {
|
|
24
|
-
DEFAULT: '#
|
|
25
|
-
yellow: '#
|
|
29
|
+
DEFAULT: '#1d1d1d',
|
|
30
|
+
yellow: '#ffed00',
|
|
26
31
|
},
|
|
27
32
|
},
|
|
28
33
|
gridTemplateColumns: {
|
|
@@ -33,22 +38,24 @@ module.exports = {
|
|
|
33
38
|
'0px 5px 5px rgba(0, 0, 0, 0.2), 0 10px 10px rgba(0, 0, 0, 0.1), 0 20px 20px rgba(0, 0, 0, 0.15)',
|
|
34
39
|
},
|
|
35
40
|
fontFamily: {
|
|
36
|
-
|
|
37
|
-
'
|
|
38
|
-
'
|
|
39
|
-
'
|
|
40
|
-
'
|
|
41
|
+
heading: [
|
|
42
|
+
'Playfair Display',
|
|
43
|
+
'Playfair Display Fallback',
|
|
44
|
+
'Playfair Display Fallback Android',
|
|
45
|
+
'serif',
|
|
41
46
|
],
|
|
42
|
-
|
|
43
|
-
'
|
|
44
|
-
'
|
|
45
|
-
'
|
|
47
|
+
body: [
|
|
48
|
+
'Inter',
|
|
49
|
+
'Inter Fallback',
|
|
50
|
+
'Inter Fallback Android',
|
|
51
|
+
'system-ui',
|
|
46
52
|
'sans-serif',
|
|
47
53
|
],
|
|
48
|
-
|
|
49
|
-
'
|
|
50
|
-
'
|
|
51
|
-
'
|
|
54
|
+
ui: [
|
|
55
|
+
'Inter',
|
|
56
|
+
'Inter Fallback',
|
|
57
|
+
'Inter Fallback Android',
|
|
58
|
+
'system-ui',
|
|
52
59
|
'sans-serif',
|
|
53
60
|
],
|
|
54
61
|
},
|
|
@@ -62,11 +69,14 @@ module.exports = {
|
|
|
62
69
|
> The `content` globs already cover `libs/**`, so feature libs added later are picked up — no edit
|
|
63
70
|
> needed when modules arrive. `darkMode` keys off `contrast-high` for the WCAG high-contrast toggle.
|
|
64
71
|
|
|
65
|
-
> **
|
|
66
|
-
>
|
|
67
|
-
>
|
|
68
|
-
|
|
69
|
-
>
|
|
72
|
+
> **Font tokens are named by role** (`heading`, `body`, `ui`), never after a typeface or a project.
|
|
73
|
+
> In reference mode the copied templates may use the source project's own token names — remap those
|
|
74
|
+
> class names onto these three in step 9 rather than re-adding the old tokens.
|
|
75
|
+
|
|
76
|
+
> **Fonts must cover Polish diacritics** (`ą ć ę ł ń ś ź ż` + uppercase). A heading face that lacks
|
|
77
|
+
> them renders titles in a silent fallback. Check the glyph coverage of any face before adopting it;
|
|
78
|
+
> the defaults above are chosen for full latin-ext support. Never leave a `fontFamily` entry as an
|
|
79
|
+
> empty array — it falls back to system sans. See `references/qa-hardening.md` §5.
|
|
70
80
|
|
|
71
81
|
## 2. postcss
|
|
72
82
|
|
|
@@ -8,8 +8,11 @@
|
|
|
8
8
|
# Portable to macOS system bash (3.2). Exit 0 = all pass; exit 1 = one or more checks failed.
|
|
9
9
|
set -eu
|
|
10
10
|
|
|
11
|
-
ROOT="${1:?usage: verify-init.sh <workspace-root> <PREFIX>}"
|
|
12
|
-
PREFIX="${2:?usage: verify-init.sh <workspace-root> <PREFIX>}"
|
|
11
|
+
ROOT="${1:?usage: verify-init.sh <workspace-root> <PREFIX> [SOURCE_ID]}"
|
|
12
|
+
PREFIX="${2:?usage: verify-init.sh <workspace-root> <PREFIX> [SOURCE_ID]}"
|
|
13
|
+
# Optional: in reference mode, the source project's slug or domain, so branding leakage from it can
|
|
14
|
+
# be checked. No project identity is hardcoded in this script.
|
|
15
|
+
SOURCE_ID="${3:-}"
|
|
13
16
|
cd "$ROOT" 2>/dev/null || { echo "ERROR: no such dir: $ROOT" >&2; exit 2; }
|
|
14
17
|
|
|
15
18
|
fail=0
|
|
@@ -26,15 +29,56 @@ grep -q "multimediaUrl" apps/web/src/server.ts && pass "multimediaUrl in server.
|
|
|
26
29
|
grep -q "/api/translations" apps/web/src/server.ts && pass "/api/translations endpoint" || bad "/api/translations in server.ts"
|
|
27
30
|
|
|
28
31
|
echo "== QA hardening (references/qa-hardening.md) =="
|
|
29
|
-
# dynamic sitemap/robots endpoints
|
|
32
|
+
# dynamic sitemap/robots endpoints — a static copy hardcodes whatever domain it was written with
|
|
30
33
|
grep -q "sitemap.xml" apps/web/src/server.ts && pass "dynamic /sitemap.xml endpoint" || bad "/sitemap.xml endpoint in server.ts (SITE_URL-driven, never a static copy)"
|
|
31
34
|
grep -q "robots.txt" apps/web/src/server.ts && pass "dynamic /robots.txt endpoint" || bad "/robots.txt endpoint in server.ts (SITE_URL-driven, never a static copy)"
|
|
32
|
-
if ls apps/web/public/favicon.ico apps/web/src/favicon.ico >/dev/null 2>&1; then pass "favicon present"; else bad "favicon.ico missing
|
|
33
|
-
# an empty fontFamily array silently falls back to system sans
|
|
34
|
-
if grep -qE "
|
|
35
|
+
if ls apps/web/public/favicon.ico apps/web/src/favicon.ico >/dev/null 2>&1; then pass "favicon present"; else bad "favicon.ico missing"; fi
|
|
36
|
+
# an empty fontFamily array silently falls back to system sans
|
|
37
|
+
if grep -qE ":[[:space:]]*\[[[:space:]]*\]" tailwind.config.js 2>/dev/null; then bad "empty fontFamily array in tailwind.config.js (heading font falls back to system sans)"; else pass "no empty fontFamily entries"; fi
|
|
35
38
|
grep -q "./lib/components" libs/shared/angular/src/index.ts && pass "shared-lib components barrel populated" || bad "components barrel in shared-lib index.ts"
|
|
39
|
+
[ -f libs/shared/angular/README.md ] && pass "shared-lib README (module skills read it)" || bad "libs/shared/angular/README.md missing — document the lib's components/services/pipes/tools/directives"
|
|
36
40
|
[ -f .claude/settings.json ] && grep -q "flow@mobilems" .claude/settings.json && pass "flow@mobilems enabled" || bad "flow@mobilems in .claude/settings.json"
|
|
37
41
|
|
|
42
|
+
echo "== Branding + SEO reset (references/branding-reset.md) =="
|
|
43
|
+
# Font tokens are named by role, never after a typeface or a project. A token named after a
|
|
44
|
+
# typeface means a copied file re-added the source project's naming.
|
|
45
|
+
if grep -qE "fontFamily:" tailwind.config.js 2>/dev/null; then
|
|
46
|
+
if grep -qE "^[[:space:]]*(heading|body|ui):" tailwind.config.js 2>/dev/null; then
|
|
47
|
+
pass "role-named font tokens"
|
|
48
|
+
else
|
|
49
|
+
bad "font tokens are not role-named (expected heading/body/ui) — see branding-reset.md §3"
|
|
50
|
+
fi
|
|
51
|
+
fi
|
|
52
|
+
# unreplaced placeholders ship literal '{{...}}' to users
|
|
53
|
+
PH="$(grep -rl "{{" tailwind.config.js apps/web/src/index.html apps/web/public/translations.json 2>/dev/null || true)"
|
|
54
|
+
if [ -n "$PH" ]; then
|
|
55
|
+
bad "unreplaced {{...}} placeholders:"
|
|
56
|
+
printf ' %s\n' $PH >&2
|
|
57
|
+
else
|
|
58
|
+
pass "no unreplaced placeholders"
|
|
59
|
+
fi
|
|
60
|
+
# In reference mode the app is copied from a source project, so its identity can travel with the
|
|
61
|
+
# code. Pass that project's slug/domain as $3 to have it checked; omit it in foundation-only mode.
|
|
62
|
+
if [ -n "${SOURCE_ID:-}" ]; then
|
|
63
|
+
LEAKID="$(grep -rilE "$SOURCE_ID" tailwind.config.js apps/web/src apps/web/public .env.dev 2>/dev/null || true)"
|
|
64
|
+
if [ -n "$LEAKID" ]; then
|
|
65
|
+
bad "source project identity ('$SOURCE_ID') still present — run step 9 (branding reset):"
|
|
66
|
+
printf ' %s\n' $LEAKID >&2
|
|
67
|
+
else
|
|
68
|
+
pass "no source project identity"
|
|
69
|
+
fi
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
echo "== Framework first (packages/shared/angular/README.md) =="
|
|
73
|
+
# masonry belongs to the framework's MasonryGridComponent — no app-level instances
|
|
74
|
+
MAS="$(grep -rlnE "new Masonry\(|MasonryInstance" libs apps/web/src 2>/dev/null || true)"
|
|
75
|
+
if [ -n "$MAS" ]; then
|
|
76
|
+
bad "hand-rolled masonry — use <smart-mobilems-masonry-grid> (MasonryGridComponent):"
|
|
77
|
+
printf ' %s\n' $MAS >&2
|
|
78
|
+
else
|
|
79
|
+
pass "no hand-rolled masonry instances"
|
|
80
|
+
fi
|
|
81
|
+
|
|
38
82
|
echo "== Foundation scope (no feature modules yet) =="
|
|
39
83
|
if ls -d libs/museum-* >/dev/null 2>&1; then bad "libs/museum-* present (feature modules are built by the module skills)"; else pass "no libs/museum-*"; fi
|
|
40
84
|
# feature routes reference a museum-* lib; loadChildren + the import often span lines, so match museum- anywhere
|
|
@@ -70,10 +114,19 @@ else
|
|
|
70
114
|
fi
|
|
71
115
|
|
|
72
116
|
echo "== Prefix threaded =="
|
|
73
|
-
|
|
74
|
-
|
|
117
|
+
# Derive the workspace's own aliases from tsconfig.base.json rather than naming any project's
|
|
118
|
+
# prefix here. Anything mapped that is neither @$PREFIX/ nor a framework scope is a leftover.
|
|
119
|
+
FOREIGN="$(grep -oE '"@[A-Za-z0-9_-]+/[A-Za-z0-9_*/-]*"' tsconfig.base.json 2>/dev/null |
|
|
120
|
+
tr -d '"' | grep -vE "^@smartsoft001" | grep -vE "^@$PREFIX/" | cut -d/ -f1 | sort -u || true)"
|
|
121
|
+
if [ -n "$FOREIGN" ]; then
|
|
122
|
+
bad "tsconfig.base.json maps a foreign workspace alias (expected @$PREFIX/):"
|
|
123
|
+
printf ' %s\n' $FOREIGN >&2
|
|
124
|
+
for a in $FOREIGN; do
|
|
125
|
+
SRC="$(grep -rl "$a/" libs/shared/angular/src apps/web/src 2>/dev/null || true)"
|
|
126
|
+
[ -n "$SRC" ] && printf ' imported in: %s\n' $SRC >&2
|
|
127
|
+
done
|
|
75
128
|
else
|
|
76
|
-
pass "
|
|
129
|
+
pass "workspace aliases use @$PREFIX/"
|
|
77
130
|
fi
|
|
78
131
|
|
|
79
132
|
echo
|
|
@@ -28,7 +28,31 @@ OWN domain entity, its OWN reducer (`getReducer`), and **no `baseQuery`**.
|
|
|
28
28
|
Run `scripts/detect-init.sh <workspace-root>`. It confirms the MobilEMS foundation is present
|
|
29
29
|
(`SharedModule.forRoot` in `app.config.ts`, a populated shared-lib barrel). If not, tell the user to
|
|
30
30
|
run `/mobilems:project-init` first. Hold `<PREFIX>` (from `tsconfig.base.json`; reference uses
|
|
31
|
-
|
|
31
|
+
own) and the reference repo path (same one init used).
|
|
32
|
+
|
|
33
|
+
## Framework first — MANDATORY
|
|
34
|
+
|
|
35
|
+
Read these before writing ANY component, service, pipe, directive or helper, and reuse what they
|
|
36
|
+
list — re-implementing framework code is a defect, not a shortcut:
|
|
37
|
+
|
|
38
|
+
0. [**The Framework API index**](https://github.com/smartsoft001/mobilems-framework/blob/main/README.md#-framework-api) — the map of every package to
|
|
39
|
+
its catalog. Start here when you do not already know which package owns what.
|
|
40
|
+
1. The framework API catalog — `packages/shared/angular/README.md` in this repo, installed as
|
|
41
|
+
`node_modules/@smartsoft001-mobilems/angular/README.md` in a museum app ([browse](https://github.com/smartsoft001/mobilems-framework/blob/main/packages/shared/angular/README.md)).
|
|
42
|
+
This is the path `scripts/verify-module.sh` names when it fails.
|
|
43
|
+
2. [`packages/articles/README.md`](https://github.com/smartsoft001/mobilems-framework/blob/main/packages/articles/README.md) — the package this module reuses
|
|
44
|
+
3. `libs/shared/angular/README.md` — the app's own shared lib (built by `mobilems-project-init`)
|
|
45
|
+
|
|
46
|
+
| Do not hand-roll | Use |
|
|
47
|
+
| ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------- |
|
|
48
|
+
| a masonry grid (`new Masonry(...)`, per-page masonry JS/CSS) | `<smart-mobilems-masonry-grid>` (`MasonryGridComponent`) with a `#masonryContentTpl`; the `Masonry` provider only feeds it |
|
|
49
|
+
| filter state / hand-built `query` arrays | `FiltersBaseComponent<MuseumThematicPath>` + its `FiltersContext` accessors |
|
|
50
|
+
| list/detail plumbing (facade wiring, id-from-route) | the `ArticlesListComponent` / `ArticlesItemComponent` base classes |
|
|
51
|
+
| a paged publication reader's content blocks | `WidgetComponent` + the `ArticleWidgetType` map |
|
|
52
|
+
| media URLs, meta/OG tags, modals, WCAG | `FileUrlService`, `SeoService`/`MetaService`, `ModalService`, `WcagService` |
|
|
53
|
+
|
|
54
|
+
Anything the framework genuinely lacks goes into `libs/shared/angular` **once** (and into its
|
|
55
|
+
README) — never a per-module copy. `scripts/verify-module.sh` fails the run on hand-rolled masonry.
|
|
32
56
|
|
|
33
57
|
## Steps
|
|
34
58
|
|
|
@@ -32,6 +32,17 @@ libs/museum-thematic-paths/
|
|
|
32
32
|
> There is **no `src/__mocks__/` dir** in this lib (objects had one; thematic-paths does not). Copy
|
|
33
33
|
> only what the reference has.
|
|
34
34
|
|
|
35
|
+
`components/filters` **must** extend the framework base class rather than build `query` arrays by
|
|
36
|
+
hand — that base is what wires the debounced writes back through `CrudFacade`:
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
export class FiltersComponent extends FiltersBaseComponent<MuseumThematicPath> {}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Read filter state through the inherited `context` accessors (`searchText`, `keywords`, `page`,
|
|
43
|
+
`sort`), never by assembling a `query` yourself. `scripts/verify-module.sh` fails the run if this
|
|
44
|
+
component does not extend `FiltersBaseComponent`.
|
|
45
|
+
|
|
35
46
|
## Domain entity (verbatim — thread nothing; pure types)
|
|
36
47
|
|
|
37
48
|
Unlike objects' `MuseumObject extends MsObject`, this entity `implements` the local interfaces — it
|
package/plugins/mobilems/skills/mobilems-thematic-publications/references/module-and-routes.md
CHANGED
|
@@ -69,6 +69,32 @@ import { routes } from './thematic-paths.routes';
|
|
|
69
69
|
export class MuseumThematicPathsModule {}
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
+
> **The `Masonry` provider exists only to feed the framework's `MasonryGridComponent`.** It is DI
|
|
73
|
+
> plumbing, not a grid — never call `new Masonry(...)`, keep a `MasonryInstance`, or re-implement the
|
|
74
|
+
> layout/`reloadItems` dance in a page component. A hand-rolled CSS-grid or column layout is the same
|
|
75
|
+
> defect. `scripts/verify-module.sh` fails the run on both.
|
|
76
|
+
|
|
77
|
+
The list page renders the grid like this — copy this shape, it is the required one:
|
|
78
|
+
|
|
79
|
+
```html
|
|
80
|
+
<smart-mobilems-masonry-grid [list]="list()" [options]="{ gutter: 24 }">
|
|
81
|
+
<ng-template #masonryContentTpl>
|
|
82
|
+
<div class="masonry-grid-sizer"></div>
|
|
83
|
+
@for (item of list(); track item.id) {
|
|
84
|
+
<div class="masonry-item">
|
|
85
|
+
<app-thematic-paths-list-item [item]="item" />
|
|
86
|
+
</div>
|
|
87
|
+
}
|
|
88
|
+
</ng-template>
|
|
89
|
+
</smart-mobilems-masonry-grid>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`.masonry-grid-sizer` and `.masonry-item` are required — they are the component's default
|
|
93
|
+
`columnWidth` / `itemSelector`. The card (lib-contents.md) is the only module-specific part. Inputs,
|
|
94
|
+
public methods and the SSR provider are documented in the framework catalog,
|
|
95
|
+
[`packages/shared/angular/README.md`](https://github.com/smartsoft001/mobilems-framework/blob/main/packages/shared/angular/README.md#masonrygridcomponent)
|
|
96
|
+
(installed as `node_modules/@smartsoft001-mobilems/angular/README.md`).
|
|
97
|
+
|
|
72
98
|
> Contrast with `mobilems-objects` (`ObjectsSharedModule.forFeature` over `MsObject`, no
|
|
73
99
|
> `reducerFactory`): here the module reuses `ArticlesSharedModule`, supplies `reducerFactory: getReducer`,
|
|
74
100
|
> and there is deliberately **no `baseQuery`** in the config.
|