Skip to content

feat: rework image background options of pages and apps EXO-90087 - #567

Merged
srenault-meeds merged 1 commit into
feature/ai-contributionfrom
feature/exip-90087-image-background-options
Sep 8, 2026
Merged

srenault-meeds merged 1 commit into
feature/ai-contributionfrom
feature/exip-90087-image-background-options

Conversation

@srenault-meeds

Copy link
Copy Markdown
Member

Implements task 90087[Layout] Suggest new options to center and fix image background of pages and apps.

Requires Meeds-io/portal#1319 (persistence) and Meeds-io/platform-ui (rendering). Companion: Meeds-io/social for the branding admin. Same EXO-90087.

Problem

Size and repeat shared a single radio group, so the four values were mutually exclusive: choosing Repeat silently cleared background-size, and "fit the whole image and tile it" was unreachable. There was also no way to center a background or to keep it fixed while scrolling.

The options, as the board specifies them

Group Options (first = default)
Size Fill, cropped (was Cover) · Fit, whole image (was Contain)
Position Center (new) · Top right · Top left · Bottom right · Bottom left
Scrolling (new) Stays fixed · Scrolls with page
Repeat No repeat · Repeat

Four independent captioned groups, two per row (col-6, with Center full width), so size and repeat now compose freely.

Changes

  • BackgroundInput.vue — the four groups; the backgroundImageStyle intermediate state is gone, each group binds its own container property. Removing the image clears all four, so a stale fixed/repeat is not re-applied to the next image.
  • LayoutModel / EntityMapper — carry backgroundAttachment and appBackgroundAttachment
  • LayoutUtils.js — defaults and parseContainerStyle
  • ApplicationUtils.js — emit the value on all four paths (site / page / app / background layer)
  • LayoutEditor_en.properties — group captions, the two renamed size labels, Center and the two Scrolling labels

Drive-by fix

backgroundPosition was never declared in the backgroundProperties of either application drawer, nor in the page drawer's appBackgroundProperties. Under Vue 2 the key was therefore non-reactive, the deep watcher never fired, and app background position was silently never saved. Now declared alongside backgroundAttachment.

Points for the reviewer

  • Labels use the board's sentence case ("Fill, cropped", "Fit, whole image"). The mockup attached to the task title-cases them ("Fill, Cropped"). Trivial to flip if the PO prefers the mockup.
  • imageSizeCover/imageSizeContain keep their keys with new English values, so Crowdin re-translates rather than orphaning keys in 40 locale files. Other locales show the old wording until it syncs.
  • No data upgrade. Existing pages keep their current rendering; Center / Stays fixed apply once a background is re-saved.

Tests

  • layout-service: 365/365 pass. npm run eslint-check: 0 errors.
  • Deployed to a local 7.3.x-ai-contribution bundle; the production build reproduces the shipped layout.war byte-for-byte for every bundle not touched here.

Knowledge: none — no architectural change; the new option follows the existing background style plumbing. A /domain-doc refresh of layout may still be worth folding into the eXip's knowledge sub-task.

🤖 Generated with Claude Code

Size and repeat used to share a single radio group, so choosing "Repeat"
silently cleared background-size and the two could never be combined.
They are now four independent, captioned groups, matching the page-builder
options the board asks for:

- Size:      Fill, cropped (was Cover, default) / Fit, whole image (was Contain)
- Position:  Center (new, default) / top right / top left / bottom right / bottom left
- Scrolling: Stays fixed (new, default) / Scrolls with page
- Repeat:    No repeat (default) / Repeat

Scrolling is backed by the new backgroundAttachment property carried
through LayoutModel and EntityMapper. Removing the image now clears all
four options, so a stale "fixed"/"repeat" is not re-applied to the next
image.

Also declares backgroundPosition on the application background objects of
the two application drawers and of the page drawer's app styling: the key
was missing, so app background position was never reactive and never saved.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
srenault-meeds added a commit to Meeds-io/platform-ui that referenced this pull request Sep 8, 2026
…XO-90087 (#1003)

Rendering side of [task
90087](https://community.exoplatform.com/portal/dw/tasks/taskDetail/90087)
— *[Layout] Suggest new options to center and fix image background of
pages and apps*.

Companions: `Meeds-io/portal#1319` (persistence), `Meeds-io/layout#567`
(editor UI), `Meeds-io/social` (branding admin). Same `EXO-90087`.

### Changes
Three declarations, each following the pattern of the
`background-repeat` / `-size` / `-position` lines right above it:

- `pagelayout.less` — `background-attachment:
var(--appBackgroundAttachment, scroll)` on the application background
rule
- `pagelayout.less` — `var(--pageBodyBackgroundAttachment, scroll)` on
`.layout-page-parent`
- `reset.less` — `var(--allPagesBackgroundAttachment, scroll)` on `body`

Each falls back to `scroll`, the CSS initial value, so every existing
background renders exactly as before until an editor stores something.

### Known limitation, worth a reviewer's eye
On **`body`** the property is inert by construction: `reset.less` sets
`body { overflow: hidden }` and `BodyScrollListener.js` (in `social`)
makes an inner element (`.page-scroll-content` / `#UIPageBody` /
`#UISiteBody`) the real scroller. A background on a viewport-sized box
that never scrolls paints identically for `fixed` and `scroll` — so the
**site-wide / branding** background cannot show a difference, and the
option is a no-op there.

Page, section and app backgrounds paint on elements *inside* that
scroller and do behave as specified: `fixed` anchors to the viewport,
`scroll` travels with the content.

The declaration is kept for consistency and so the value is not silently
dropped. Making it meaningful site-wide would mean repainting the
all-pages background on the scroll container instead of `body` — a wider
change than this task warrants, deliberately left out.

Knowledge: none — three CSS declarations, no architectural change.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
@sonarqubecloud

sonarqubecloud Bot commented Sep 8, 2026

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
0.0% Coverage on New Code (required ≥ 60%)

See analysis details on SonarQube Cloud

@srenault-meeds
srenault-meeds merged commit 4830f8b into feature/ai-contribution Sep 8, 2026
5 of 10 checks passed
@srenault-meeds
srenault-meeds deleted the feature/exip-90087-image-background-options branch September 8, 2026 18:29
exo-swf pushed a commit to Meeds-io/platform-ui that referenced this pull request Sep 9, 2026
…XO-90087 (#1003)

Rendering side of [task
90087](https://community.exoplatform.com/portal/dw/tasks/taskDetail/90087)
— *[Layout] Suggest new options to center and fix image background of
pages and apps*.

Companions: `Meeds-io/portal#1319` (persistence), `Meeds-io/layout#567`
(editor UI), `Meeds-io/social` (branding admin). Same `EXO-90087`.

### Changes
Three declarations, each following the pattern of the
`background-repeat` / `-size` / `-position` lines right above it:

- `pagelayout.less` — `background-attachment:
var(--appBackgroundAttachment, scroll)` on the application background
rule
- `pagelayout.less` — `var(--pageBodyBackgroundAttachment, scroll)` on
`.layout-page-parent`
- `reset.less` — `var(--allPagesBackgroundAttachment, scroll)` on `body`

Each falls back to `scroll`, the CSS initial value, so every existing
background renders exactly as before until an editor stores something.

### Known limitation, worth a reviewer's eye
On **`body`** the property is inert by construction: `reset.less` sets
`body { overflow: hidden }` and `BodyScrollListener.js` (in `social`)
makes an inner element (`.page-scroll-content` / `#UIPageBody` /
`#UISiteBody`) the real scroller. A background on a viewport-sized box
that never scrolls paints identically for `fixed` and `scroll` — so the
**site-wide / branding** background cannot show a difference, and the
option is a no-op there.

Page, section and app backgrounds paint on elements *inside* that
scroller and do behave as specified: `fixed` anchors to the viewport,
`scroll` travels with the content.

The declaration is kept for consistency and so the value is not silently
dropped. Making it meaningful site-wide would mean repainting the
all-pages background on the scroll container instead of `body` — a wider
change than this task warrants, deliberately left out.

Knowledge: none — three CSS declarations, no architectural change.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
exo-swf pushed a commit that referenced this pull request Sep 9, 2026
Implements [task
90087](https://community.exoplatform.com/portal/dw/tasks/taskDetail/90087)
— *[Layout] Suggest new options to center and fix image background of
pages and apps*.

Requires `Meeds-io/portal#1319` (persistence) and `Meeds-io/platform-ui`
(rendering). Companion: `Meeds-io/social` for the branding admin. Same
`EXO-90087`.

### Problem
Size and repeat shared a **single** radio group, so the four values were
mutually exclusive: choosing *Repeat* silently cleared
`background-size`, and "fit the whole image **and** tile it" was
unreachable. There was also no way to center a background or to keep it
fixed while scrolling.

### The options, as the board specifies them
| Group | Options (first = default) |
|---|---|
| Size | Fill, cropped *(was Cover)* · Fit, whole image *(was Contain)*
|
| Position | **Center** *(new)* · Top right · Top left · Bottom right ·
Bottom left |
| Scrolling *(new)* | **Stays fixed** · Scrolls with page |
| Repeat | No repeat · Repeat |

Four independent captioned groups, two per row (`col-6`, with Center
full width), so size and repeat now compose freely.

### Changes
- **`BackgroundInput.vue`** — the four groups; the
`backgroundImageStyle` intermediate state is gone, each group binds its
own container property. Removing the image clears all four, so a stale
`fixed`/`repeat` is not re-applied to the next image.
- **`LayoutModel` / `EntityMapper`** — carry `backgroundAttachment` and
`appBackgroundAttachment`
- **`LayoutUtils.js`** — defaults and `parseContainerStyle`
- **`ApplicationUtils.js`** — emit the value on all four paths (site /
page / app / background layer)
- **`LayoutEditor_en.properties`** — group captions, the two renamed
size labels, Center and the two Scrolling labels

### Drive-by fix
`backgroundPosition` was never declared in the `backgroundProperties` of
either application drawer, nor in the page drawer's
`appBackgroundProperties`. Under Vue 2 the key was therefore
non-reactive, the deep watcher never fired, and **app background
position was silently never saved**. Now declared alongside
`backgroundAttachment`.

### Points for the reviewer
- **Labels use the board's sentence case** ("Fill, cropped", "Fit, whole
image"). The mockup attached to the task title-cases them ("Fill,
Cropped"). Trivial to flip if the PO prefers the mockup.
- **`imageSizeCover`/`imageSizeContain` keep their keys** with new
English values, so Crowdin re-translates rather than orphaning keys in
40 locale files. Other locales show the old wording until it syncs.
- **No data upgrade.** Existing pages keep their current rendering;
Center / Stays fixed apply once a background is re-saved.

### Tests
- `layout-service`: 365/365 pass. `npm run eslint-check`: 0 errors.
- Deployed to a local 7.3.x-ai-contribution bundle; the production build
reproduces the shipped `layout.war` byte-for-byte for every bundle not
touched here.

Knowledge: none — no architectural change; the new option follows the
existing background style plumbing. A `/domain-doc` refresh of `layout`
may still be worth folding into the eXip's knowledge sub-task.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
srenault-meeds added a commit that referenced this pull request Sep 9, 2026
…EXO-90087 (#568)

Follow-up to `#567` (merged), for [task
90087](https://community.exoplatform.com/portal/dw/tasks/taskDetail/90087).
Requires `Meeds-io/platform-ui#1004`.

Same translation as `Meeds-io/portal#1320`, applied to the **site**
background written by the site layout editor.

The site background paints on the scrolling container
(`Meeds-io/platform-ui#1004`), where `background-attachment: scroll`
means *"fixed with regard to that box"* and so looks identical to
`fixed`. `local` is what makes it follow the scrolled content:

```js
function siteBackgroundAttachment(attachment) {
  return attachment === 'scroll' ? 'local' : attachment;
}
```

Applied only on the `options.siteStyle` path of `getStyle`.

### Deliberately not applied elsewhere
**Page, section and app backgrounds keep `scroll` untranslated.** They
paint on elements *inside* that scroller (`.layout-page-parent`, the
section/app elements), which physically move as the container scrolls —
so `scroll`, meaning "fixed with regard to the element's own box",
already makes the background travel with the content. `fixed` there
correctly anchors to the viewport.

That asymmetry is the whole point of the helper: the surface determines
the CSS keyword, while the stored value keeps the user's intent (`fixed`
/ `scroll`) uniformly across every background.

### Tests
`npm run eslint-check`: 0 errors. Production bundles rebuilt and
deployed to a local 7.3.x-ai-contribution bundle (eval-free AMD,
verified).

Knowledge: none — one value translation, no architectural change.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Jihed525 added a commit that referenced this pull request Sep 9, 2026
…rolling, repeat EXO-90087 (#569)

Backport of
[EXO-90087](https://community.exoplatform.com/portal/dw/tasks/taskDetail/90087)
— *[N2] [Layout] Suggest new options to center and fix image background
of pages and apps* — from `feature/ai-contribution` onto `develop`.
**layout part** of a four-repo ticket, and the one that depends on the
others.

## Scope

Two `-x`-stamped cherry-picks of the FB squash-merges, applied to a
fresh `origin/develop` with **no conflict**:

| FB PR | Commit | Change |
|---|---|---|
| #567 | `d2aa07f5` | rework the image background options of pages and
apps — Size (Fill / Fit), Position (Center default + corners), Scrolling
(Stays fixed / Scrolls with page), Repeat |
| #568 | `3f724575` | translate the site background attachment for the
scroll container |

9 files: `LayoutModel` and `EntityMapper` in `layout-service` (the new
`backgroundAttachment` / `appBackgroundAttachment` fields and their two
mapping lines — DTO mapping, **not** a JPA entity); the page and
application editor drawers, `BackgroundInput.vue`, `LayoutUtils.js`,
`ApplicationUtils.js` and `LayoutEditor_en.properties` in
`layout-webapp`.

## The four halves and their merge order

| Repo | PR | Depends on |
|---|---|---|
| **portal** | [#1321](Meeds-io/portal#1321) | —
|
| **platform-ui** |
[#1005](Meeds-io/platform-ui#1005) | portal
(runtime) |
| **social** | [#6091](Meeds-io/social#6091) |
portal (runtime) |
| **layout** (this PR) | — | **portal (compile time)** — `EntityMapper`
calls `ModelStyle#setBackgroundAttachment`, which portal#1321 adds |

**Merge this one last, after portal#1321.** On today's `develop` this PR
does not compile — `setBackgroundAttachment` does not exist there yet —
so expect the PR build to stay red until portal#1321 has landed and the
`7.3.x-SNAPSHOT` has been republished.

## Verification

Built on a fresh `origin/develop` worktree **against the portal#1321
artefact installed locally** (`mvn clean install` on the portal backport
first, then `mvn -o clean install` here so the snapshot could not be
replaced by the remote one mid-build): **BUILD SUCCESS, 365 tests, 0
failures, 0 errors, 0 skipped**, all four modules green. A guard checked
that the installed `portal.component.api` jar actually carried the new
`app-background-attachment` key before the build started — the first
attempt had found the remote snapshot in its place.

## Classification: N2

Shared UI component + DTO model fields. No ACL, schema, entity, bridge,
upload or MCP surface (the `EntityMapper` here is the Storage-layer
mapper, not a persistence entity). Matches the ticket's own `[N2]`.
**Its approver must be an Architect/Senior Developer who knows it is N2,
not an approval on AI review alone.** Author ≠ approver.

Validated on the FB acceptance by the PO (Samuel Renault) and tested by
me, 2026-09-09.

Knowledge: none — mechanical backport; the knowledge for this ticket is
owed by the FB delivery, not by this PR.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Samuel Renault <58853195+srenault-meeds@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant