Files
pictureFrame-webApp/.claude/skills/oro-frontend-dev/SKILL.md
T
football2801 a536baabd6 feat: initial commit — BMAD tooling, Claude memories, firmware scaffold
Adds the complete project foundation:
- BMAD BMM workflow tooling (_bmad/)
- Claude slash commands, skills, and project memories (.claude/)
- ESP32 firmware scaffold (PlatformIO + Waveshare e-ink driver)
- .gitignore excluding _bmad-output/ and .pio/ build artifacts

Planning artifacts (PRD, architecture, epics) are intentionally not
tracked — they live in _bmad-output/ per project convention.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 15:38:46 -04:00

403 lines
11 KiB
Markdown

---
name: oro-frontend-dev
description: OroCommerce frontend development reference covering storefront themes, back-office themes, layouts, SCSS, JavaScript architecture (Chaplin/Backbone), page components, templates, and asset management. Use when customizing the storefront UI, modifying admin templates, writing JS components, or styling OroCommerce pages.
---
# OroCommerce Frontend Developer
Reference for frontend/UI development on OroCommerce.
Full docs: https://doc.oroinc.com/frontend/
## Two Theme Systems
OroCommerce has two separate theme architectures:
| Area | Framework | Templates | JS | Docs |
|---|---|---|---|---|
| Storefront | OroLayouts (SEO-friendly, no SPA) | Layout YAML + Twig blocks | Chaplin/Backbone | https://doc.oroinc.com/frontend/storefront/ |
| Back-office | Placeholders (SPA-like, Twig+Underscore) | Twig extends @OroUI | Chaplin/Backbone | https://doc.oroinc.com/frontend/back-office/ |
Themes are NOT interchangeable between storefront and back-office.
## Storefront Theming
### Theme Structure
```
Resources/views/layouts/{theme_name}/
theme.yml # theme definition (label, parent, icon)
config/
assets.yml # SCSS entry points
jsmodules.yml # JS module registration
datagrids.yml # frontend datagrid configs
templates/ # Twig block templates
page/ # per-page layout overrides
```
### theme.yml
Basic:
```yaml
label: 'My Custom Theme'
parent: default
icon: bundles/mybundle/images/theme-icon.png
groups: [commerce]
rtl_support: true
```
Full configuration with admin-selectable options:
```yaml
label: 'Acme Theme'
parent: default
groups: [commerce]
rtl_support: true
configuration:
sections:
header:
label: Header
options:
promotional_content:
label: oro_frontend.theme.default.configuration.header.promotional_content.label
type: content_block_selector
options:
required: false
standalone_main_menu:
label: oro_frontend.theme.default.configuration.header.standalone_main_menu.label
type: checkbox
default: checked
previews:
checked: 'bundles/orofrontend/images/previews/menu-standalone.png'
unchecked: 'bundles/orofrontend/images/previews/menu-hamburger.png'
product_listing:
label: 'oro.product.theme.default.configuration.product_listing.label'
options:
filters_position:
label: 'oro.product.theme.default.configuration.product_listing.filters_position.label'
type: radio
default: sidebar
values:
top: 'oro.product.theme.default.configuration.product_listing.filters_position.values.top'
sidebar: 'oro.product.theme.default.configuration.product_listing.filters_position.values.sidebar'
```
Configuration option types: `content_block_selector`, `menu_selector`, `checkbox`, `radio`, `select`.
### Layout Updates
Layout updates are YAML files that modify page structure:
```yaml
layout:
actions:
- '@setBlockTheme':
id: page_container
themes: '@MyBundle/layouts/my_theme/page/layout.html.twig'
- '@add':
id: my_custom_block
parentId: page_content
blockType: text
options:
text: '=data["locale"].getLanguage()'
- '@remove':
id: unwanted_block
- '@move':
id: existing_block
parentId: new_parent
```
Place layout updates in route-specific directories to target individual pages:
```
Resources/views/layouts/{theme}/
layout.yml # global layout (all pages)
oro_frontend_root/frontend_root.yml # homepage
oro_product_frontend_product_index/product_index.yml # PLP
oro_product_frontend_product_view/product_view.yml # PDP
oro_checkout_frontend_checkout/checkout.yml # checkout
```
### Block Types
| blockType | Purpose |
|---|---|
| `container` | Wraps child blocks with a div |
| `text` | Static text or expression |
| `block` | Custom Twig-rendered block |
| `content_block` | References admin-managed content block by `alias` |
| `menu` | Renders a navigation menu |
### Layout Data Expressions
Access data providers and context variables in YAML options:
```yaml
options:
vars:
# Data provider methods (registered via layout_data_provider tag)
topCategories: '=data["category_provider"].getRootCategoriesWithSlugs()'
featuredCount: '=data["product_provider"].getFeaturedProductCount()'
ctaLinks: '=data["cta_link_provider"].getLinks(data["menu"].getMenu("commerce_main_menu"))'
# Context variables (route params, request attributes)
category: '=data["category_provider"].getCategoryById(context["category_id"])'
```
### @addTree Action
Add multiple blocks at once:
```yaml
- '@addTree':
items:
footer_menu:
blockType: menu
options:
item: '=data["menu"].getMenu("commerce_footer_links")'
depth: 2
tree:
page_footer_base:
footer_menu: ~
```
### @setBlockTheme with Multiple Files
```yaml
- '@setBlockTheme':
themes:
- 'templates/layout.html.twig'
- 'templates/page-footer/footer_branding.html.twig'
- 'templates/navigation/sidebar_menu.html.twig'
```
### Twig Block Naming Convention
Block names in layout Twig templates follow: `_{blockId}_widget`
```twig
{% block _my_custom_block_widget %}
<div {{ block('block_attributes') }}>
{{ block_widget(block) }}
</div>
{% endblock %}
```
### SCSS / Stylesheets
Register SCSS in `config/assets.yml`:
```yaml
styles:
inputs:
- 'bundles/acmetheme/scss/styles.scss'
output: 'css/styles.css'
```
Recommended SCSS directory organization:
```
scss/
styles.scss # main entry point (@import all)
variables/
_colors.scss # color palette as Sass maps
_typography.scss
_mixins.scss
components/
_product-cards.scss
_buttons.scss
layout/
_page-header.scss
_page-footer.scss
_product-view.scss
_product-index.scss
_checkout.scss
navigation/
_sidebar.scss
_topbar.scss
```
Color palette using Sass maps (Oro pattern):
```scss
@use 'sass:map';
$theme-color-palette: (
'brand': (
'primary': #424242,
'secondary': #A89571,
),
'semantic': (
'success': #005E1F,
'error': #D32F2F,
)
) !default;
$color-palette: map.deep-merge($color-palette, $theme-color-palette);
```
Access via `get-var-color('brand', 'primary')`. Build: `php bin/console oro:assets:build`.
### SVG Icons
Custom icons go in the theme's icons directory. Register via theme config.
## Back-Office Theming
### Twig Template Overrides
Override admin templates by mirroring directory structure under `Resources/views/`.
Common base templates to extend:
- `@OroUI/actions/index.html.twig` -- list/grid pages
- `@OroUI/actions/view.html.twig` -- detail/view pages
- `@OroUI/actions/update.html.twig` -- create/edit form pages
Use Oro UI macros for consistent rendering:
```twig
{% import '@OroUI/macros.html.twig' as UI %}
{{ UI.renderProperty('Label', value) }}
{{ UI.renderHtmlProperty('HTML Label', htmlValue) }}
```
### Placeholders
Inject content into predefined back-office page regions.
```yaml
# Resources/config/oro/placeholders.yml
placeholders:
oro_view_additional_data:
items:
my_custom_section:
order: 50
template: '@AcmeExample/Placeholder/section.html.twig'
applicable: '@acme.placeholder_filter->isApplicable'
```
Common placeholder targets:
- `oro_view_additional_data` -- entity view page extra sections
- `oro_widget_side_bar` -- sidebar widgets
- `oro_title_before` / `oro_title_after` -- title area
Conditional rendering via `applicable` filter (service method returning bool).
Placeholders are back-office only; use Layout Updates for storefront.
### SCSS
Override admin SCSS variables or add new stylesheets via theme settings.
## JavaScript Architecture
Built on Chaplin.js (extends Backbone.js). Key concepts:
### Page Components
The primary extension mechanism. Define in HTML via data attributes:
```html
<div data-page-component-module="mybundle/js/app/components/my-component"
data-page-component-options="{{ options|json_encode }}">
</div>
```
Component lifecycle: created on `page:update`, disposed on page change.
### JS Module Registration
Register modules in `Resources/config/jsmodules.yml`:
```yaml
dynamic-imports:
mybundle:
- mybundle/js/app/components/my-component
aliases:
jquery$: oroui/js/extend/jquery
# Override an existing module with custom implementation
map:
'*':
'orofrontend/js/app/datafilter/frontend-multiselect-decorator': 'acmetheme/js/custom-multiselect-decorator'
```
### App Modules
Execute code at application startup (auto-initialized on every page):
```yaml
app-modules:
- acmetheme/js/app/modules/inventory-checker
- acmetheme/js/app/modules/checkout-shipping-options
```
### AMD Module Pattern
Oro's JS uses AMD `define()` with the `oroui/js/mediator` for cross-component communication:
```javascript
define(function(require) {
'use strict';
const mediator = require('oroui/js/mediator');
const $ = require('jquery');
class MyComponent {
constructor() {
$(document).ready(() => {
mediator.on('checkout:shipping-method:rendered', this.onShippingRendered);
});
}
onShippingRendered() {
// DOM manipulation after Oro renders shipping methods
}
}
new MyComponent();
return MyComponent;
});
```
Key mediator events: `checkout:shipping-method:rendered`, `filters-manager:after-applying-state`, `page:update`, `page:afterChange`.
### Page Events
System events during page lifecycle:
1. `page:beforeChange`
2. `page:request`
3. `page:update` -- content is updated, init components
4. `page:afterChange` -- all components initialized
### File Naming Convention
```
js/app/
components/ # PageComponent implementations
controllers/ # Chaplin controllers (rare -- PageController handles all)
models/ # Backbone models and collections
views/ # Backbone views
modules/ # App modules (startup code)
templates/ # Underscore.js templates (*.html)
```
## Asset Build
```bash
php bin/console oro:assets:build # build all themes
php bin/console oro:assets:build --watch # watch mode for dev
php bin/console assets:install # symlink public assets
```
Requires Node.js >= 22 and NPM > 10.
## RTL Support
Enable Right-to-Left UI via theme configuration.
See: https://doc.oroinc.com/frontend/rtl-support/
## Additional Resources
- Storefront how-to guides: https://doc.oroinc.com/frontend/storefront/how-to/
- JS modularity deep-dive: https://doc.oroinc.com/frontend/javascript/javascript-modularity/
- Storefront design/style guide (Figma): https://doc.oroinc.com/frontend/storefront-style-guide/