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
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
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.
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
CRITICAL: All URLs must use Rsx::Route() or Rsx.Route(). Raw URLs like
"/contacts" will produce errors.
@@ -833,3 +868,4 @@ SEE ALSO
routing(3) - URL generation and route patterns
modals(3) - Modal dialogs in SPA context
ajax_error_handling(3) - Error handling patterns
scss(3) - SCSS scoping conventions and component-first philosophy