diff --git a/app/RSpade/man/scss.txt b/app/RSpade/man/scss.txt index 98f9b762d..aa1aecde7 100755 --- a/app/RSpade/man/scss.txt +++ b/app/RSpade/man/scss.txt @@ -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 + +
+
+ <%= content('toolbar') %> +
+
+ <%= content('body') %> +
+
+
+ + // Page provides content via slots + + + + + + + + + + + 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: diff --git a/app/RSpade/man/spa.txt b/app/RSpade/man/spa.txt index 4ab0183dc..3dbe11532 100755 --- a/app/RSpade/man/spa.txt +++ b/app/RSpade/man/spa.txt @@ -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: + renders as: +
+ + renders as: +
+ + 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 diff --git a/docs/CLAUDE.dist.md b/docs/CLAUDE.dist.md index 4556c9828..13cb1d7f0 100644 --- a/docs/CLAUDE.dist.md +++ b/docs/CLAUDE.dist.md @@ -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. **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 -/* my_component.scss - Scoped to component */ -.My_Component { /* Matches component class or @rsx_id */ - .content { padding: 20px; } - /* All component-specific rules here */ -} -``` +**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. -**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