Foundations
Spacing & Layout
The Bootstrap-derived spacing scale (4px steps), the per-component border-radius scale (6 / 8 / 10px), the box-shadow depths, the fixed sidebar/header dimensions, and the responsive breakpoints every micro-frontend lays out against.
Spacing scale & gutters
There are no bespoke $spacing-* tokens. Spacing derives from Bootstrap’s $spacers map where the unit $spacer = 1rem = 16px, scaling in 4px increments. Pages apply it through utilities (.p-1/.p-2/.p-3 = 4/8/16px) or hardcoded pixel values that match the scale (6, 8, 12, 16px). The main scroll container, .layout-content, uses a fixed responsive gutter rather than utilities.
The scale, to size
Each bar is one $spacers step rendered at its true pixel width. Step 3 (16px) is the base rhythm unit.
// @rvn/shared-styles — bootstrap/_variables.scss ($spacer = 1rem = 16px)
$spacer: 1rem !default;
$spacers: (
0: 0,
1: math.div($spacer, 4), // 4px
2: math.div($spacer, 2), // 8px
3: $spacer, // 16px
4: $spacer * 1.5, // 24px
5: $spacer * 3, // 48px
6: $spacer * 4, // 64px
7: $spacer * 6, // 96px
8: $spacer * 8, // 128px
9: $spacer * 10, // 160px
10: $spacer * 12, // 192px
11: $spacer * 14, // 224px
12: $spacer * 16, // 256px
) !default;
$grid-gutter-width: 1.5rem !default; // 24px — Bootstrap .row > .col gutter| Name | Type | Default | Description |
|---|---|---|---|
$spacer | 1rem | 16px | The base unit; the whole scale multiplies off it. |
step 1 | $spacer / 4 | 4px | Tightest gap — .p-1 / .m-1, vertical menu-item margin. |
step 2 | $spacer / 2 | 8px | .p-2 / .m-2, sidebar-content vertical padding. |
step 3 | $spacer | 16px | .p-3 / .m-3 — the base rhythm; layout-content side gutter (desktop). |
step 4 | $spacer * 1.5 | 24px | Also $grid-gutter-width — Bootstrap .row > .col column gutter. |
step 5–12 | $spacer * 3…16 | 48–256px | Large section spacing (48, 64, 96, 128, 160, 192, 224, 256px). |
.layout-content | padding | 12px 16px 0 16px | Main scroll container: 16px sides / 12px top / 0 bottom (desktop). |
Responsive content gutter
// administrator-fe/src/assets/scss/layout.scss — the main scroll container
.layout-content {
padding: 12px 16px 0 16px; // desktop: 16px sides, 12px top, 0 bottom
flex: 1 1 auto;
min-height: 0;
overflow-y: auto;
}
// Tablet + mobile: sides tighten to 12px
@media (max-width: 991.98px) {
.layout-content { padding: 12px 12px 0 12px; }
}
@media (max-width: 767.98px) {
.layout-content { padding: 12px 12px 0 12px; }
}.layout-content keeps 0 bottom padding so the sticky AppFormFooter pins flush to the viewport. report-fe diverges with 40px bottom (a SAS requirement), which breaks footer visibility on small screens — don’t copy that.Border radius
Radii are assigned per component, hardcoded rather than pulled from Bootstrap’s $border-radius (4px) default. The house scale is 6px for menu items and buttons, 8px for cards, popups and the sticky footer, and 10px for status badges.
The radius steps
4px collapsed-logo tile · 6px menu item / button · 8px card / popup / footer · 10px badge.
// Per-component radii — hardcoded, NOT the Bootstrap $border-radius (4px) default.
.sidebar-menu :deep(.ant-menu-item),
.sidebar-menu :deep(.ant-menu-submenu-title) {
border-radius: 6px; // menu items & buttons
}
.raffles-sidebar-popup { border-radius: 8px; } // popups & cards
.app-form-footer { border-radius: 8px; } // sticky footer bar
.logo-collapsed { border-radius: 4px; } // collapsed logo tile
.badge-rvn { border-radius: 10px !important; } // status badges| Name | Type | Default | Description |
|---|---|---|---|
logo-collapsed | border-radius | 4px | Collapsed sidebar logo tile. |
menu item / button | border-radius | 6px | .ant-menu-item, .ant-menu-submenu-title and primary/action buttons. |
card / popup / footer | border-radius | 8px | .raffles-sidebar-popup, cards, and the .app-form-footer sticky bar. |
badge-rvn | border-radius | 10px !important | Status badges (see Components → Badge). |
$border-radius | .25rem | 4px | Bootstrap default — present for framework consistency but overridden per component. |
Elevation (shadows)
Bootstrap ships an sm / md / lg depth scale at 0.075–0.175 black opacity. Layout chrome uses two custom depths instead: a directional rail shadow and a softer popup shadow.
Layout shadows
The sidebar casts a directional 2px 0 4px shadow to the right; popups float on a softer 0 6px 16px.
Bootstrap depth scale (sm / md / lg)
The framework scale, available via $box-shadow-* — used for utility-driven elevation.
// @rvn/shared-styles — bootstrap/_variables.scss (Bootstrap depth scale)
$box-shadow-sm: 0 .125rem .25rem rgba($black, .075) !default; // sm
$box-shadow: 0 .5rem 1rem rgba($black, .15) !default; // md
$box-shadow-lg: 0 1rem 3rem rgba($black, .175) !default; // lg
$box-shadow-inset: inset 0 1px 2px rgba($black, .075) !default;
// Applied in layout.scss — custom depths, not the scale above:
.azure-sidebar { box-shadow: 2px 0 4px rgba(0, 0, 0, 0.1); } // rail
.raffles-sidebar-popup{ box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12); } // popup| Name | Type | Default | Description |
|---|---|---|---|
$box-shadow-sm | 0 .125rem .25rem | rgba(0,0,0,.075) | Subtle lift — resting cards, hover states. |
$box-shadow | 0 .5rem 1rem | rgba(0,0,0,.15) | Medium — dropdowns, raised surfaces. |
$box-shadow-lg | 0 1rem 3rem | rgba(0,0,0,.175) | Large — modals, overlays. |
sidebar rail | 2px 0 4px | rgba(0,0,0,0.1) | Directional shadow to the right of .azure-sidebar. |
sidebar popup | 0 6px 16px | rgba(0,0,0,0.12) | Flyout popup for the collapsed rail (.raffles-sidebar-popup). |
.azure-sidebar { box-shadow: 2px 0 4px rgba(0,0,0,0.1) } is a bare global rule. When several MFEs inject their own copy into the shared appshell <head>, the last-loaded one wins — the same collision risk as background and border colours. Scope any override under an .azure-sidebar--<module> modifier.Breakpoints & dimensions
Layout responds at Bootstrap’s breakpoints. Below md (768px) the persistent rail is swapped for a <Drawer> overlay so it no longer squeezes content. A handful of fixed dimensions keep the chrome stable: the header is 64px tall, the sidebar header is 42px, and the collapsed rail is 42px wide.
Responsive breakpoints
// @rvn/shared-styles — bootstrap/_variables.scss
$grid-breakpoints: (
xs: 0,
sm: 576px,
md: 768px,
lg: 992px,
xl: 1200px,
xxl: 1400px
) !default;
// Custom rules use 767.98px / 991.98px to match Bootstrap's exclusive @media
// (AntD treats 768px as inclusive; Bootstrap media queries stop at 767.98px).| Name | Type | Default | Description |
|---|---|---|---|
sm | breakpoint | 576px | Below this (xs), sidebar-header padding tightens to 12px. |
md | breakpoint | 768px | Below this the rail becomes a Drawer overlay; content gutter is 12px. |
lg | breakpoint | 992px | Desktop rail rendered; content gutter widens to 16px. |
xl / xxl | breakpoint | 1200 / 1400px | Wide desktops — no bespoke layout rules. |
header line-height | fixed | 64px | .ant-layout-header — the top-bar height (header-fe index.scss). |
sidebar-header | min-height | 42px | Collapsed sidebar header row; padding 6px 16px. |
collapsed rail | width | 42px | AntD collapsed <Sider>; menu items shrink to 26px height / 9px padding-left. |
menu item | height | 48px | Expanded desktop item; margin 4px 0 (does not collapse — 8px visual gap). |
Fixed chrome dimensions
// administrator-fe/src/assets/scss/layout.scss + header-fe/src/assets/scss/index.scss
.sidebar-header { min-height: 42px; padding: 6px 16px; border-bottom: 1px solid #e1e5e9; }
.sidebar-content { padding: 8px 0; height: calc(100vh - 120px); }
.sidebar-menu :deep(.ant-menu-item),
.sidebar-menu :deep(.ant-menu-submenu-title) { height: 48px; margin: 4px 0; }
// Collapsed rail = 42px wide → items shrink (only override height + padding-left)
.azure-sidebar.ant-layout-sider-collapsed {
.ant-menu-item, .ant-menu-submenu-title { height: 26px !important; padding-left: 9px !important; }
}
.ant-layout-header { line-height: 64px !important; } // fixed top-bar heightmd: 768px, but the layout rules key off max-width: 767.98px (and 991.98px) so a viewport at exactly 768px counts as desktop — matching Bootstrap’s exclusive @media behaviour rather than AntD’s inclusive breakpoint..sidebar-header { min-height: 42px; padding: 6px 16px; }
.sidebar-content { padding: 8px 0; }
.sidebar-menu :deep(.ant-menu-item) { height: 48px; margin: 4px 0; border-radius: 6px; }
.azure-sidebar.ant-layout-sider-collapsed .ant-menu-item {
height: 26px !important; padding-left: 9px !important;
}