Document SCSS component-first architecture philosophy

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root
2025-12-12 01:13:50 +00:00
parent 84136be744
commit 958da28f64
3 changed files with 108 additions and 10 deletions

View File

@@ -42,6 +42,66 @@ DESCRIPTION
Key principle: The SCSS filename must match the filename of its Key principle: The SCSS filename must match the filename of its
associated .js (action/component) or .blade.php file. associated .js (action/component) or .blade.php file.
COMPONENT-FIRST PHILOSOPHY
Every styled element should be a component. If an element needs custom
styles, it deserves a name, a jqhtml definition, and scoped SCSS. This
eliminates CSS spaghetti - generic classes like .page-header, .filter-bar,
.action-buttons scattered across files, overriding each other unpredictably.
Pattern Recognition:
When building a page, ask: "Is this structure unique, or a pattern?"
Pattern (shared structure):
A datagrid page with toolbar, tabs, filters, and search appears
on 8 different pages. Create Datagrid_Card once with slots, use
it everywhere. Changes propagate automatically.
Unique (one-off structure):
A project dashboard with custom widgets specific to that page.
Create Project_Dashboard for that page alone.
Decision heuristic: If you're about to copy-paste structural markup,
stop and extract a component.
Slot-Based Composition:
Use slots to separate structure from content. The component owns
layout and styling; pages provide the variable parts via slots.
// Datagrid_Card owns the structure
<Define:Datagrid_Card>
<div class="card">
<div class="card-header">
<%= content('toolbar') %>
</div>
<div class="card-body">
<%= content('body') %>
</div>
</div>
</Define:Datagrid_Card>
// Page provides content via slots
<Datagrid_Card>
<Slot:toolbar>
<button>Add New</button>
<Search_Input />
</Slot:toolbar>
<Slot:body>
<Contacts_Datagrid />
</Slot:body>
</Datagrid_Card>
This keeps pages declarative and components reusable.
What Remains Shared:
Only primitives should be shared/unscoped styles:
- Buttons (.btn-primary, .btn-secondary)
- Spacing utilities (.mb-3, .p-2)
- Typography (.text-muted, .fw-bold)
- Bootstrap overrides
Everything else - page layouts, card variations, custom UI patterns -
should be component-scoped SCSS.
SCOPING RULES SCOPING RULES
Files in rsx/app/**/*.scss and rsx/theme/components/**/*.scss: Files in rsx/app/**/*.scss and rsx/theme/components/**/*.scss:

View File

@@ -423,6 +423,41 @@ SUBLAYOUTS
To access intermediate layouts, use DOM traversal or layout hooks. To access intermediate layouts, use DOM traversal or layout hooks.
STYLING
SPA actions and layouts are jqhtml components, so they automatically
receive their class name on the root DOM element. This enables scoped
SCSS styling.
Automatic Class Assignment:
<Define:Contacts_Index_Action> renders as:
<div class="Contacts_Index_Action Component Spa_Action ...">
<Define:Frontend_Layout> renders as:
<div class="Frontend_Layout Component Spa_Layout ...">
SCSS File Pairing:
Each action/layout can have a companion SCSS file with all styles
scoped to the component class:
// rsx/app/frontend/contacts/contacts_index_action.scss
.Contacts_Index_Action {
.filters { margin-bottom: 1rem; }
.contact-list { ... }
}
// rsx/app/frontend/frontend_layout.scss
.Frontend_Layout {
.app-sidebar { width: 250px; }
.app-content { margin-left: 250px; }
}
Enforcement:
SCSS files in rsx/app/ must wrap all rules in a single class
matching the action/layout name. This is enforced by the manifest
scanner and prevents CSS conflicts between pages.
See scss man page for complete scoping rules and philosophy.
URL GENERATION URL GENERATION
CRITICAL: All URLs must use Rsx::Route() or Rsx.Route(). Raw URLs like CRITICAL: All URLs must use Rsx::Route() or Rsx.Route(). Raw URLs like
"/contacts" will produce errors. "/contacts" will produce errors.
@@ -833,3 +868,4 @@ SEE ALSO
routing(3) - URL generation and route patterns routing(3) - URL generation and route patterns
modals(3) - Modal dialogs in SPA context modals(3) - Modal dialogs in SPA context
ajax_error_handling(3) - Error handling patterns ajax_error_handling(3) - Error handling patterns
scss(3) - SCSS scoping conventions and component-first philosophy

View File

@@ -430,19 +430,21 @@ The process involves creating Action classes with @route decorators and converti
**NO inline styles, scripts, or event handlers** - Use companion `.scss` and `.js` files. **NO inline styles, scripts, or event handlers** - Use companion `.scss` and `.js` files.
**jqhtml components** work fully in Blade (no slots). **jqhtml components** work fully in Blade (no slots).
### SCSS Pairing ### SCSS Component-First Architecture
For page/component-specific styles, wrap all rules in a class matching the component name: **Philosophy**: Every styled element is a component. If it needs custom styles, give it a name, a jqhtml definition, and scoped SCSS. This eliminates CSS spaghetti - generic classes overriding each other unpredictably across files.
```scss **Recognition**: When building a page, ask: "Is this structure unique, or a pattern?" A datagrid page with toolbar, tabs, filters, and search is a *pattern* - create `Datagrid_Card` once with slots, use it everywhere. A one-off project dashboard is *unique* - create `Project_Dashboard` for that page. If you're about to copy-paste structural markup, stop and extract a component.
/* my_component.scss - Scoped to component */
.My_Component { /* Matches component class or @rsx_id */
.content { padding: 20px; }
/* All component-specific rules here */
}
```
**Convention**: Each Blade view, jqhtml action, or component automatically gets its name as a class on its root element, enabling scoped styling. **Composition**: Use slots to separate structure from content. The component owns layout and styling; pages provide the variable parts via slots. This keeps pages declarative and components reusable.
**Enforcement**: SCSS in `rsx/app/` and `rsx/theme/components/` must wrap in a single component class matching the jqhtml/blade file. This works because all jqhtml components, SPA actions/layouts, and Blade views with `@rsx_id` automatically render with `class="Component_Name"` on their root element. `rsx/lib/` is for non-visual plumbing (validators, utilities). `rsx/theme/` (outside components/) holds primitives, variables, Bootstrap overrides.
**Variables**: Define shared values (colors, spacing, border-radius) in `rsx/theme/variables.scss` or similar. These must be explicitly included before directory includes in bundle definitions. Component-local variables can be defined within the scoped rule.
**Supplemental files**: Multiple SCSS files can target the same component (e.g., breakpoint-specific styles) if a primary file with matching filename exists.
Details: `php artisan rsx:man scss`
### JavaScript for Blade Pages ### JavaScript for Blade Pages