Add SCSS class scoping enforcement, move modal to lib, cleanup legacy files 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
353 lines
11 KiB
Plaintext
Executable File
353 lines
11 KiB
Plaintext
Executable File
NAME
|
|
scss - SCSS file organization and class scoping conventions
|
|
|
|
SYNOPSIS
|
|
Action-scoped SCSS for SPA actions and Blade views:
|
|
|
|
// rsx/app/frontend/dashboard/dashboard_index_action.scss
|
|
.Dashboard_Index_Action {
|
|
.card { ... }
|
|
.stats-grid { ... }
|
|
}
|
|
|
|
Component-scoped SCSS for theme components:
|
|
|
|
// rsx/theme/components/sidebar/sidebar_nav.scss
|
|
.Sidebar_Nav {
|
|
.nav-item { ... }
|
|
.nav-link { ... }
|
|
}
|
|
|
|
Variables may be declared outside the wrapper for sharing:
|
|
|
|
// rsx/app/frontend/frontend_spa_layout.scss
|
|
$sidebar-width: 215px;
|
|
$header-height: 57px;
|
|
|
|
.Frontend_Spa_Layout {
|
|
.sidebar { width: $sidebar-width; }
|
|
}
|
|
|
|
DESCRIPTION
|
|
RSX enforces a class-scoping convention for SCSS files to prevent CSS
|
|
conflicts and ensure styles are self-contained. Every SCSS file in
|
|
rsx/app/ or rsx/theme/components/ must wrap ALL rules inside a single
|
|
top-level class selector that matches its associated JavaScript class
|
|
or Blade view ID.
|
|
|
|
This is essentially manual CSS scoping - like CSS Modules but enforced
|
|
by convention. The benefit is predictable specificity, no conflicts
|
|
between pages/components, and self-documenting file organization.
|
|
|
|
Key principle: The SCSS filename must match the filename of its
|
|
associated .js (action/component) or .blade.php file.
|
|
|
|
SCOPING RULES
|
|
|
|
Files in rsx/app/**/*.scss and rsx/theme/components/**/*.scss:
|
|
|
|
Must be fully enclosed in a class matching either:
|
|
- A Component subclass (Spa_Action, Spa_Layout, or direct Component)
|
|
- A Blade view's @rsx_id value (server-rendered page styles)
|
|
|
|
The SCSS filename must match the associated JS or Blade file's
|
|
filename (with .scss extension instead of .js/.blade.php).
|
|
|
|
Example - SPA Action:
|
|
rsx/app/frontend/dashboard/Dashboard_Index_Action.js
|
|
rsx/app/frontend/dashboard/dashboard_index_action.scss
|
|
|
|
// dashboard_index_action.scss
|
|
.Dashboard_Index_Action {
|
|
// ALL styles nested here
|
|
}
|
|
|
|
Example - SPA Layout:
|
|
rsx/app/frontend/Frontend_Spa_Layout.js
|
|
rsx/app/frontend/frontend_spa_layout.scss
|
|
|
|
// frontend_spa_layout.scss
|
|
.Frontend_Spa_Layout {
|
|
// ALL layout styles nested here
|
|
.app-sidebar { ... }
|
|
.app-content { ... }
|
|
}
|
|
|
|
Example - Blade View:
|
|
rsx/app/login/login_index.blade.php // has @rsx_id('Login_Index')
|
|
rsx/app/login/login_index.scss
|
|
|
|
// login_index.scss
|
|
.Login_Index {
|
|
// ALL styles nested here
|
|
}
|
|
|
|
Example - Theme Component:
|
|
rsx/theme/components/sidebar/sidebar_nav.js
|
|
rsx/theme/components/sidebar/sidebar_nav.scss
|
|
|
|
// sidebar_nav.scss
|
|
.Sidebar_Nav {
|
|
// ALL styles nested here
|
|
}
|
|
|
|
Files elsewhere:
|
|
SCSS files outside these paths are not validated by this rule
|
|
and can be organized as needed (e.g., global utilities, variables
|
|
in rsx/theme/base/).
|
|
|
|
SCSS VARIABLES
|
|
|
|
SCSS variable declarations ($var: value;) are allowed OUTSIDE the
|
|
wrapper class. This enables variables to be shared when the file is
|
|
imported by other SCSS files.
|
|
|
|
Example - Variables outside wrapper:
|
|
|
|
// frontend_spa_layout.scss
|
|
$sidebar-width: 215px;
|
|
$header-height: 57px;
|
|
$mobile-breakpoint: 991.98px;
|
|
|
|
.Frontend_Spa_Layout {
|
|
.sidebar {
|
|
width: $sidebar-width;
|
|
}
|
|
.header {
|
|
height: $header-height;
|
|
}
|
|
}
|
|
|
|
The manifest scanner strips variable declarations before checking
|
|
for the wrapper class, so they do not cause validation failures.
|
|
|
|
VARIABLES-ONLY FILES
|
|
|
|
Files containing ONLY variable declarations and comments (no actual
|
|
CSS rules or selectors) are considered valid without a wrapper class.
|
|
These are typically partial files intended to be imported by others.
|
|
|
|
Example - Variables-only file (valid):
|
|
|
|
// _variables.scss
|
|
$primary-color: #0d6efd;
|
|
$secondary-color: #6c757d;
|
|
$border-radius: 0.375rem;
|
|
|
|
Such files are marked with scss_variables_only in the manifest and
|
|
skip wrapper validation entirely.
|
|
|
|
SUPPLEMENTAL SCSS FILES
|
|
|
|
When a single SCSS file becomes unwieldy, you can split styles into
|
|
multiple files. Supplemental SCSS files may have different filenames
|
|
as long as:
|
|
|
|
1. A primary SCSS file exists with the matching filename (e.g.,
|
|
frontend_spa_layout.scss for Frontend_Spa_Layout)
|
|
2. The supplemental file uses the SAME wrapper class as the primary
|
|
|
|
This allows organizing styles by breakpoint, feature, or logical
|
|
grouping while maintaining the scoping convention.
|
|
|
|
Example - Splitting by breakpoint:
|
|
|
|
rsx/app/frontend/
|
|
frontend_spa_layout.scss // Primary file (required)
|
|
frontend_spa_layout_mobile.scss // Supplemental - mobile styles
|
|
frontend_spa_layout_print.scss // Supplemental - print styles
|
|
|
|
// frontend_spa_layout.scss (primary)
|
|
.Frontend_Spa_Layout {
|
|
.sidebar { width: 215px; }
|
|
.header { height: 57px; }
|
|
}
|
|
|
|
// frontend_spa_layout_mobile.scss (supplemental)
|
|
.Frontend_Spa_Layout {
|
|
@media (max-width: 768px) {
|
|
.sidebar { width: 100%; }
|
|
.header { height: 48px; }
|
|
}
|
|
}
|
|
|
|
// frontend_spa_layout_print.scss (supplemental)
|
|
.Frontend_Spa_Layout {
|
|
@media print {
|
|
.sidebar { display: none; }
|
|
.no-print { display: none; }
|
|
}
|
|
}
|
|
|
|
The primary file MUST exist first. Without it, supplemental files
|
|
will fail validation with a filename mismatch error.
|
|
|
|
BENEFITS
|
|
|
|
No CSS Conflicts:
|
|
.notice-item in Dashboard_Index_Action won't affect .notice-item
|
|
in Calendar_Index_Action because they're in different scope wrappers.
|
|
|
|
Self-Documenting:
|
|
File name tells you exactly which action/component it styles.
|
|
Delete the action -> delete its SCSS -> no orphaned styles.
|
|
|
|
Simple Class Names:
|
|
Use .team-grid instead of .dashboard-index-action__team-grid.
|
|
The wrapper provides the scoping automatically.
|
|
|
|
Predictable Specificity:
|
|
All page/component styles get the same specificity boost from
|
|
being nested under their wrapper class.
|
|
|
|
Safe Refactoring:
|
|
Moving or renaming an action means moving/renaming its SCSS.
|
|
No hunting through global stylesheets for related rules.
|
|
|
|
HOW IT WORKS
|
|
|
|
jqhtml components and Spa_Action classes automatically add their
|
|
class name to the root DOM element. For example, a component defined
|
|
as <Define:Sidebar_Nav> will have class="Sidebar_Nav" on its root.
|
|
|
|
Blade views use @rsx_id('View_Name') which can be output to the DOM
|
|
for the same scoping effect.
|
|
|
|
The manifest scanner detects if an SCSS file is fully enclosed in
|
|
a single class rule by:
|
|
1. Removing comments
|
|
2. Stripping SCSS variable declarations ($var: value;)
|
|
3. Checking if remaining content matches pattern: .ClassName { ... }
|
|
4. Verifying bracket balance (all content inside the wrapper)
|
|
|
|
A code quality rule then validates:
|
|
1. The wrapper class exists (or file is variables-only)
|
|
2. It matches a valid Component subclass or Blade @rsx_id
|
|
3. The filename matches the associated file
|
|
|
|
NO EXEMPTIONS
|
|
|
|
There are NO exemptions to this rule for files in rsx/app/ or
|
|
rsx/theme/components/. Every SCSS file in these directories must
|
|
be scoped to its associated action, layout, component, or view.
|
|
|
|
If a file cannot be associated with any of these (extremely rare),
|
|
it likely belongs elsewhere:
|
|
- rsx/theme/base/ for global utilities and variables
|
|
- rsx/theme/layouts/ for shared layout styles
|
|
- A dedicated partial imported via @use
|
|
|
|
Moving files outside the enforced directories requires explicit
|
|
developer approval and should be carefully considered. In 99% of
|
|
cases, the SCSS file should be properly scoped.
|
|
|
|
VALIDATION
|
|
|
|
The scoping rule is enforced at manifest build time. Violations
|
|
produce errors like:
|
|
|
|
SCSS file 'rsx/app/frontend/dashboard/dashboard.scss' must be
|
|
fully enclosed in a single class rule matching a Component
|
|
or Blade @rsx_id.
|
|
|
|
Expected: .Dashboard_Index_Action { ... }
|
|
Found: No wrapper class detected
|
|
|
|
Or for wrapper class mismatches:
|
|
|
|
SCSS wrapper class 'Frontend_Dashboard' does not match any
|
|
Component class or Blade @rsx_id
|
|
|
|
Or for filename mismatches:
|
|
|
|
SCSS filename 'styles.scss' must match associated Component
|
|
file 'dashboard_index_action'
|
|
|
|
EXAMPLES
|
|
|
|
Correct - SPA Action Styles:
|
|
|
|
// rsx/app/frontend/invoices/invoices_view_action.scss
|
|
.Invoices_View_Action {
|
|
.invoice-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.line-items {
|
|
.item-row {
|
|
border-bottom: 1px solid #eee;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.invoice-header {
|
|
flex-direction: column;
|
|
}
|
|
}
|
|
}
|
|
|
|
Correct - Layout with Variables:
|
|
|
|
// rsx/app/frontend/frontend_spa_layout.scss
|
|
$sidebar-width: 215px;
|
|
$header-height: 57px;
|
|
|
|
.Frontend_Spa_Layout {
|
|
.app-sidebar {
|
|
width: $sidebar-width;
|
|
position: fixed;
|
|
}
|
|
|
|
.app-header {
|
|
height: $header-height;
|
|
}
|
|
}
|
|
|
|
Correct - Component Styles:
|
|
|
|
// rsx/theme/components/modal/rsx_modal.scss
|
|
.Rsx_Modal {
|
|
.modal-header {
|
|
border-bottom: 1px solid var(--border-color);
|
|
}
|
|
|
|
.modal-body {
|
|
padding: 1.5rem;
|
|
}
|
|
|
|
&.modal-lg {
|
|
.modal-dialog {
|
|
max-width: 800px;
|
|
}
|
|
}
|
|
}
|
|
|
|
Incorrect - Multiple Top-Level Rules:
|
|
|
|
// BAD: Multiple selectors at top level
|
|
.Dashboard_Index_Action {
|
|
.card { ... }
|
|
}
|
|
|
|
.sidebar { // ERROR: This is outside the wrapper
|
|
width: 200px;
|
|
}
|
|
|
|
Incorrect - No Wrapper:
|
|
|
|
// BAD: No wrapper class
|
|
.card {
|
|
padding: 1rem;
|
|
}
|
|
|
|
.stats-grid {
|
|
display: grid;
|
|
}
|
|
|
|
SEE ALSO
|
|
spa - SPA routing and actions
|
|
jqhtml - Component template system
|
|
coding_standards - General naming conventions
|
|
code_quality - Code quality rule system
|