@flusys/ng-layout 6.3.0 → 6.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +152 -11
  2. package/assets/layout/base/_brand.scss +44 -0
  3. package/assets/layout/{_core.scss → base/_core.scss} +8 -1
  4. package/assets/layout/{_footer.scss → base/_footer.scss} +1 -1
  5. package/assets/layout/{_forms.scss → base/_forms.scss} +3 -3
  6. package/assets/layout/base/_menu.scss +52 -0
  7. package/assets/layout/base/_rtl.scss +230 -0
  8. package/assets/layout/base/_topbar.scss +132 -0
  9. package/assets/layout/base/variables/_common.scss +62 -0
  10. package/assets/layout/classic/_main.scss +14 -0
  11. package/assets/layout/classic/_menu.scss +77 -0
  12. package/assets/layout/classic/_responsive.scss +95 -0
  13. package/assets/layout/classic/_rtl.scss +26 -0
  14. package/assets/layout/classic/_topbar.scss +53 -0
  15. package/assets/layout/{_topbar_nav.scss → classic/_topbar_nav.scss} +45 -17
  16. package/assets/layout/classic/classic.scss +6 -0
  17. package/assets/layout/layout.scss +18 -16
  18. package/assets/layout/modern/_menu.scss +98 -0
  19. package/assets/layout/modern/_responsive.scss +93 -0
  20. package/assets/layout/modern/_rtl.scss +24 -0
  21. package/assets/layout/modern/_shell.scss +59 -0
  22. package/assets/layout/modern/_sidebar.scss +101 -0
  23. package/assets/layout/modern/_topbar.scss +37 -0
  24. package/assets/layout/modern/_variables.scss +114 -0
  25. package/assets/layout/modern/modern.scss +7 -0
  26. package/fesm2022/flusys-ng-layout.mjs +1353 -954
  27. package/fesm2022/flusys-ng-layout.mjs.map +1 -1
  28. package/package.json +4 -4
  29. package/types/flusys-ng-layout.d.ts +175 -65
  30. package/assets/layout/_main.scss +0 -13
  31. package/assets/layout/_menu.scss +0 -188
  32. package/assets/layout/_responsive.scss +0 -128
  33. package/assets/layout/_rtl.scss +0 -482
  34. package/assets/layout/_topbar.scss +0 -215
  35. package/assets/layout/variables/_common.scss +0 -20
  36. /package/assets/layout/{_mixins.scss → base/_mixins.scss} +0 -0
  37. /package/assets/layout/{_preloading.scss → base/_preloading.scss} +0 -0
  38. /package/assets/layout/{_typography.scss → base/_typography.scss} +0 -0
  39. /package/assets/layout/{_utils.scss → base/_utils.scss} +0 -0
  40. /package/assets/layout/{variables → base/variables}/_dark.scss +0 -0
  41. /package/assets/layout/{variables → base/variables}/_light.scss +0 -0
@@ -0,0 +1,98 @@
1
+ // Modern look for the shared <app-menu> structure (see base/_menu.scss), scoped to
2
+ // the sidebar the same way the classic look is.
3
+ .layout-modern-sidebar .layout-menu {
4
+ // The brand row sits directly above, so the list carries its own breathing room.
5
+ padding-top: 0.5rem;
6
+
7
+ // The one scroll region in the sidebar: the brand row above and the footer below
8
+ // stay pinned. `min-height: 0` lets this list shrink below its content height
9
+ // inside the flex column instead of pushing the footer off-screen.
10
+ flex: 1 1 auto;
11
+ min-height: 0;
12
+ overflow-y: auto;
13
+ overscroll-behavior: contain;
14
+ -webkit-overflow-scrolling: touch;
15
+ // A hairline scrollbar tinted from the canvas ink — visible enough to signal the
16
+ // overflow without cutting a grey gutter into the fixed-width column.
17
+ scrollbar-width: thin;
18
+ scrollbar-color: color-mix(in srgb, var(--layout-modern-ink) 40%, transparent)
19
+ transparent;
20
+
21
+ &::-webkit-scrollbar {
22
+ width: 0.25rem;
23
+ }
24
+
25
+ &::-webkit-scrollbar-track {
26
+ background: transparent;
27
+ }
28
+
29
+ &::-webkit-scrollbar-thumb {
30
+ background-color: color-mix(
31
+ in srgb,
32
+ var(--layout-modern-ink) 40%,
33
+ transparent
34
+ );
35
+ border-radius: 999px;
36
+ }
37
+
38
+ &::-webkit-scrollbar-thumb:hover {
39
+ background-color: color-mix(
40
+ in srgb,
41
+ var(--layout-modern-ink) 60%,
42
+ transparent
43
+ );
44
+ }
45
+
46
+ li {
47
+ margin-top: 2px;
48
+ }
49
+
50
+ ul {
51
+ a {
52
+ color: var(--layout-modern-ink);
53
+ padding: 0.6875rem 0.75rem;
54
+ border-radius: var(--layout-modern-item-radius);
55
+ font-size: 0.875rem;
56
+ font-weight: 500;
57
+
58
+ .layout-menuitem-icon {
59
+ margin-inline-end: 0.75rem;
60
+ font-size: 1rem;
61
+ }
62
+
63
+ .layout-submenu-toggler {
64
+ opacity: 0.85;
65
+ }
66
+
67
+ &:not(.active-route):hover {
68
+ background-color: var(--layout-modern-item-hover);
69
+ }
70
+
71
+ &.active-route {
72
+ background-color: var(--layout-modern-item-active);
73
+ color: var(--layout-modern-item-active-color);
74
+ font-weight: 600;
75
+ box-shadow: var(--layout-modern-item-shadow);
76
+ // The preset's accent bar (0 for Aura and Nora, 3px for Lara), drawn in the
77
+ // row's own ink so it reads on the chip in both light and dark themes.
78
+ border-inline-start: var(--f-menuitem-active-border-width, 0px) solid
79
+ currentColor;
80
+ }
81
+ }
82
+
83
+ // Nested levels indent through the list, not per-item margins.
84
+ ul {
85
+ padding-inline-start: 0.75rem;
86
+ }
87
+ }
88
+
89
+ li.active-menuitem > a {
90
+ background-color: var(--layout-modern-item-hover);
91
+ border-radius: var(--layout-modern-item-radius);
92
+ }
93
+
94
+ li.active-menuitem > a.active-route {
95
+ background-color: var(--layout-modern-item-active);
96
+ color: var(--layout-modern-item-active-color);
97
+ }
98
+ }
@@ -0,0 +1,93 @@
1
+ // Desktop overlay mode — sidebar floats above the canvas instead of holding a column.
2
+ @media (min-width: 992px) {
3
+ .layout-modern.layout-modern-overlay {
4
+ .layout-modern-sidebar {
5
+ position: fixed;
6
+ z-index: var(--layout-sidebar-z);
7
+ inset-block: 0;
8
+ inset-inline-start: 0;
9
+ width: var(--layout-modern-sidebar-width);
10
+ flex-basis: var(--layout-modern-sidebar-width);
11
+ margin-inline-start: 0;
12
+ background: var(--layout-modern-canvas);
13
+ box-shadow: var(--layout-modern-shadow);
14
+ transform: translateX(-100%);
15
+ }
16
+
17
+ .layout-modern-main {
18
+ margin-inline-start: var(--layout-modern-card-margin);
19
+ }
20
+
21
+ &.layout-modern-overlay-active .layout-modern-sidebar {
22
+ transform: translateX(0);
23
+ }
24
+ }
25
+ }
26
+
27
+ // Tablet and below — sidebar becomes a drawer over a mask.
28
+ @media (max-width: 991px) {
29
+ .layout-modern {
30
+ // The sidebar is a drawer down here, so the gradient canvas has nothing sitting on
31
+ // it — a frame of it around the card reads as a stray coloured border rather than
32
+ // as the shell. Let the card fill the viewport instead; the canvas still shows
33
+ // through on the drawer itself, which carries the same gradient.
34
+ // Units, not a bare 0: both feed calc() expressions (--layout-shell-topbar-bottom
35
+ // among them), where a unitless <number> invalidates the whole expression.
36
+ --layout-modern-card-margin: 0px;
37
+ --layout-modern-radius: 0px;
38
+
39
+ .layout-modern-sidebar {
40
+ position: fixed;
41
+ z-index: var(--layout-sidebar-z);
42
+ inset-block: 0;
43
+ inset-inline-start: 0;
44
+ width: var(--layout-modern-sidebar-width);
45
+ flex-basis: var(--layout-modern-sidebar-width);
46
+ background: var(--layout-modern-canvas);
47
+ box-shadow: var(--layout-modern-shadow);
48
+ transform: translateX(-100%);
49
+ }
50
+
51
+ .layout-modern-mask {
52
+ display: none;
53
+ position: fixed;
54
+ inset: 0;
55
+ z-index: var(--layout-mask-z);
56
+ background-color: var(--maskbg);
57
+ }
58
+
59
+ &.layout-modern-mobile-active {
60
+ .layout-modern-sidebar {
61
+ transform: translateX(0);
62
+ }
63
+
64
+ .layout-modern-mask {
65
+ display: block;
66
+ }
67
+ }
68
+
69
+ // A desktop collapse left over from a wider viewport must not push the drawer
70
+ // off-screen — down here the drawer is driven by transform, not by margin.
71
+ &.layout-modern-static-inactive .layout-modern-sidebar {
72
+ margin-inline-start: 0;
73
+ }
74
+ }
75
+ }
76
+
77
+ // The compact topbar itself is shared (see base/_topbar.scss); this skin only tightens
78
+ // its own geometry tokens, which the shared rules read.
79
+ @media (max-width: 1023.98px) {
80
+ .layout-modern {
81
+ --layout-topbar-inline-padding: 1rem;
82
+ }
83
+ }
84
+
85
+ @media (max-width: 639px) {
86
+ .layout-modern {
87
+ --layout-topbar-height: 4rem;
88
+
89
+ .layout-modern-content {
90
+ padding: 1rem 0.875rem 1.25rem;
91
+ }
92
+ }
93
+ }
@@ -0,0 +1,24 @@
1
+ // The shell is built on logical properties; only the drawer transform needs mirroring.
2
+ @media (min-width: 992px) {
3
+ html[dir='rtl'] .layout-modern.layout-modern-overlay {
4
+ .layout-modern-sidebar {
5
+ transform: translateX(100%);
6
+ }
7
+
8
+ &.layout-modern-overlay-active .layout-modern-sidebar {
9
+ transform: translateX(0);
10
+ }
11
+ }
12
+ }
13
+
14
+ @media (max-width: 991px) {
15
+ html[dir='rtl'] .layout-modern {
16
+ .layout-modern-sidebar {
17
+ transform: translateX(100%);
18
+ }
19
+
20
+ &.layout-modern-mobile-active .layout-modern-sidebar {
21
+ transform: translateX(0);
22
+ }
23
+ }
24
+ }
@@ -0,0 +1,59 @@
1
+ // The component hosts must not sit between the flex container and its item, or the
2
+ // sidebar/topbar lose their flex sizing and full-height stretch.
3
+ app-modern-sidebar,
4
+ app-modern-topbar {
5
+ display: contents;
6
+ }
7
+
8
+ // Shell: gradient canvas holding a transparent sidebar and an elevated content card.
9
+ .layout-modern {
10
+ display: flex;
11
+ align-items: stretch;
12
+ height: var(--layout-viewport-height);
13
+ overflow: hidden;
14
+ background: var(--layout-modern-canvas);
15
+ background-attachment: fixed;
16
+ }
17
+
18
+ .layout-modern-main {
19
+ flex: 1 1 auto;
20
+ min-width: 0;
21
+ display: flex;
22
+ flex-direction: column;
23
+ margin: var(--layout-modern-card-margin);
24
+ margin-inline-start: 0;
25
+ background-color: var(--layout-modern-surface);
26
+ border-radius: var(--layout-modern-radius);
27
+ box-shadow: var(--layout-modern-shadow);
28
+ transition: margin var(--layout-section-transition-duration);
29
+ // Deliberately not `overflow: hidden` — the topbar dropdowns (theme panel, profile,
30
+ // launcher) are absolutely positioned inside this card and size themselves against
31
+ // the viewport, so clipping here would cut them off. The rows below round their own
32
+ // outer corners instead, which keeps the card's silhouette without the clipping.
33
+ }
34
+
35
+ .layout-modern-content {
36
+ flex: 1 1 auto;
37
+ min-height: 0;
38
+ // `overflow-y: auto` also makes the inline axis scrollable, so page content stays
39
+ // inside these corners even without a clip on the card itself.
40
+ overflow-y: auto;
41
+ border-end-start-radius: var(--layout-modern-radius);
42
+ border-end-end-radius: var(--layout-modern-radius);
43
+ padding: 1.25rem 1.5rem 1.75rem;
44
+ }
45
+
46
+ .layout-modern-mask {
47
+ display: none;
48
+ }
49
+
50
+ // Collapsed sidebar (desktop): pull it out of flow and close the gap.
51
+ .layout-modern.layout-modern-static-inactive {
52
+ .layout-modern-sidebar {
53
+ margin-inline-start: calc(-1 * var(--layout-modern-sidebar-width));
54
+ }
55
+
56
+ .layout-modern-main {
57
+ margin-inline-start: var(--layout-modern-card-margin);
58
+ }
59
+ }
@@ -0,0 +1,101 @@
1
+ @use '../base/mixins' as *;
2
+
3
+ .layout-modern-sidebar {
4
+ width: var(--layout-modern-sidebar-width);
5
+ flex: 0 0 var(--layout-modern-sidebar-width);
6
+ display: flex;
7
+ flex-direction: column;
8
+ padding: 0 0.875rem 1.25rem;
9
+ color: var(--layout-modern-ink);
10
+ // Brand row and footer stay pinned — the menu list is the only scroll region,
11
+ // so the sidebar itself must never grow a scrollbar of its own.
12
+ overflow: hidden;
13
+ user-select: none;
14
+ transition:
15
+ margin-inline-start var(--layout-section-transition-duration),
16
+ transform var(--layout-section-transition-duration);
17
+
18
+ // The component host adds no box of its own, so `.layout-menu` is the flex item
19
+ // between the brand row and the footer (see modern/_menu.scss for its scrolling).
20
+ > app-menu {
21
+ display: contents;
22
+ }
23
+
24
+ .layout-modern-brand {
25
+ display: flex;
26
+ align-items: center;
27
+ gap: 0.625rem;
28
+ height: var(--layout-topbar-height);
29
+ flex: 0 0 var(--layout-topbar-height);
30
+ padding-inline: 0.25rem;
31
+ }
32
+
33
+ .layout-brand-logo {
34
+ color: var(--layout-modern-ink);
35
+
36
+ // The drawer keeps its full width on every viewport, so there is always room for
37
+ // the company name — undo the narrow-screen hide the shared brand applies.
38
+ span {
39
+ display: inline;
40
+ }
41
+ }
42
+
43
+ .layout-modern-menu-button {
44
+ margin-inline-start: auto;
45
+ display: inline-flex;
46
+ align-items: center;
47
+ justify-content: center;
48
+ width: 2rem;
49
+ height: 2rem;
50
+ flex-shrink: 0;
51
+ padding: 0;
52
+ border: 0;
53
+ border-radius: var(--layout-modern-control-radius);
54
+ background: transparent;
55
+ color: var(--layout-modern-ink);
56
+ cursor: pointer;
57
+ transition: background-color var(--element-transition-duration);
58
+
59
+ &:hover {
60
+ background-color: var(--layout-modern-item-hover);
61
+ }
62
+
63
+ &:focus-visible {
64
+ @include focused();
65
+ }
66
+
67
+ ui-icon {
68
+ font-size: 1.125rem;
69
+ }
70
+ }
71
+ }
72
+
73
+ .layout-modern-sidebar-footer {
74
+ flex: 0 0 auto;
75
+ padding-top: 1rem;
76
+ border-top: var(--layout-modern-divider-width) solid
77
+ var(--layout-modern-divider);
78
+
79
+ .layout-footer {
80
+ justify-content: flex-start;
81
+ gap: 0.5rem;
82
+ padding: 0;
83
+ border-top: 0;
84
+ font-size: 0.8125rem;
85
+ color: var(--layout-modern-ink-muted);
86
+
87
+ a {
88
+ color: var(--layout-modern-ink);
89
+ }
90
+
91
+ // Same reasoning as the brand above — the drawer has room for the whole line.
92
+ span {
93
+ display: inline;
94
+ }
95
+
96
+ .logo-image {
97
+ height: 1.5rem;
98
+ max-width: 2rem;
99
+ }
100
+ }
101
+ }
@@ -0,0 +1,37 @@
1
+ // Bar itself, plus the two things only this skin puts in it: the brand block that
2
+ // appears while the sidebar is a drawer, and the page title. The action rail is
3
+ // shared — see base/_topbar.scss.
4
+ .layout-modern-topbar {
5
+ // Own stacking context above the content (the table's sticky thead is z-10),
6
+ // but below dialogs (z-40) so a modal still covers the shell.
7
+ position: relative;
8
+ z-index: 30;
9
+ display: flex;
10
+ align-items: center;
11
+ gap: 1rem;
12
+ height: var(--layout-topbar-height);
13
+ flex: 0 0 var(--layout-topbar-height);
14
+ padding-inline: var(--layout-topbar-inline-padding);
15
+ background-color: var(--layout-modern-panel);
16
+ // Same preset tokens the classic bar reads (classic/_topbar.scss), floored at a
17
+ // hairline: this bar divides two panels inside the card, so it always needs a line.
18
+ border-bottom: var(--layout-modern-topbar-border-width) solid
19
+ var(--surface-border);
20
+ box-shadow: var(--f-topbar-shadow);
21
+ // The card no longer clips its children (see modern/_shell.scss), so the topbar
22
+ // rounds its own top corners to keep the silhouette.
23
+ border-start-start-radius: var(--layout-modern-radius);
24
+ border-start-end-radius: var(--layout-modern-radius);
25
+
26
+ .layout-modern-page-title {
27
+ // Shrinks to an ellipsis instead of pushing the actions off the bar.
28
+ flex: 0 1 auto;
29
+ min-width: 0;
30
+ font-size: 0.9375rem;
31
+ font-weight: 500;
32
+ color: var(--text-color-secondary);
33
+ overflow: hidden;
34
+ text-overflow: ellipsis;
35
+ white-space: nowrap;
36
+ }
37
+ }
@@ -0,0 +1,114 @@
1
+ // Modern skin tokens — every colour resolves from the active @flusys/ng-ui theme,
2
+ // so switching preset / primary / surface repaints the shell automatically.
3
+ .layout-modern {
4
+ // Geometry overrides for this skin — everything else (viewport height, stacking
5
+ // order, content padding) comes from the shared tokens in base/variables/_common.
6
+ --layout-modern-sidebar-width: 19rem;
7
+ --layout-modern-gap: 1.125rem;
8
+ // The gap around the content card. Narrower viewports shrink it (see
9
+ // modern/_responsive.scss); everything that has to line up with the card's edges
10
+ // reads this one token rather than repeating the value.
11
+ --layout-modern-card-margin: var(--layout-modern-gap);
12
+
13
+ // Preset-driven geometry. The active preset (Aura / Lara / Nora) publishes the same
14
+ // shell tokens the classic skin reads in classic/_menu.scss and classic/_topbar.scss,
15
+ // so this skin resolves its chrome from them instead of hard-coding it — switching
16
+ // preset now restyles both skins. min() / max() clamp each value into this skin's own
17
+ // range: its card and rows stay softer than a classic sidebar's, while a square preset
18
+ // still squares them and a heavy-bordered one still thickens its lines.
19
+ --layout-modern-radius: calc(var(--f-card-border-radius, 12px) + 2px);
20
+ --layout-modern-item-radius: min(
21
+ var(--f-menuitem-active-radius, 9999px),
22
+ 0.625rem
23
+ );
24
+ --layout-modern-control-radius: min(var(--f-border-radius-lg, 8px), 0.5rem);
25
+ --layout-modern-topbar-border-width: max(
26
+ var(--f-topbar-border-width, 1px),
27
+ 1px
28
+ );
29
+ --layout-modern-divider-width: max(var(--f-sidebar-border-width, 1px), 1px);
30
+
31
+ // Shared topbar tokens, retuned for a bar that sits inside the content card.
32
+ --layout-topbar-height: 4.5rem;
33
+ --layout-topbar-inline-padding: 1.5rem;
34
+ --layout-topbar-actions-gap: 0.75rem;
35
+ --layout-topbar-group-gap: 0.5rem;
36
+ --layout-topbar-action-icon-size: 1.125rem;
37
+
38
+ // The topbar sits inside the card, so it ends one card margin lower than in a
39
+ // skin whose topbar is flush with the viewport.
40
+ --layout-shell-topbar-bottom: calc(
41
+ var(--layout-topbar-height) + var(--layout-modern-card-margin)
42
+ );
43
+
44
+ // Ink used on top of the gradient canvas — every canvas tint derives from it.
45
+ --layout-modern-ink: var(--f-primary-contrast-color);
46
+ --layout-modern-ink-muted: color-mix(
47
+ in srgb,
48
+ var(--layout-modern-ink) 78%,
49
+ transparent
50
+ );
51
+ --layout-modern-item-hover: color-mix(
52
+ in srgb,
53
+ var(--layout-modern-ink) 16%,
54
+ transparent
55
+ );
56
+ --layout-modern-divider: color-mix(
57
+ in srgb,
58
+ var(--layout-modern-ink) 30%,
59
+ transparent
60
+ );
61
+
62
+ --layout-modern-canvas: linear-gradient(
63
+ 150deg,
64
+ var(--f-primary-300) 0%,
65
+ var(--f-primary-500) 34%,
66
+ var(--f-primary-600) 68%,
67
+ var(--f-primary-700) 100%
68
+ );
69
+ --layout-modern-item-active: var(--f-surface-900);
70
+ --layout-modern-item-active-color: var(--f-surface-0);
71
+ --layout-modern-panel: var(--surface-card);
72
+ --layout-modern-surface: var(--surface-ground);
73
+ --layout-modern-shadow: 0 18px 46px -22px rgb(0 0 0 / 55%);
74
+ --layout-modern-item-shadow: 0 6px 14px -8px rgb(0 0 0 / 60%);
75
+ }
76
+
77
+ // A preset with no radius at all wants none here either. The clamps above are
78
+ // written to keep this skin softer than a classic sidebar, which would otherwise
79
+ // leave the card and its rows slightly rounded in a deliberately square preset.
80
+ :root[data-f-preset='Nora'] .layout-modern {
81
+ --layout-modern-radius: 0px;
82
+ --layout-modern-item-radius: 0px;
83
+ --layout-modern-control-radius: 0px;
84
+ }
85
+
86
+ // A neutral primary — the "noir" swatch, and the Nora preset's signature — resolves
87
+ // the primary ramp to the surface greys. The light-mode canvas would then fade to a
88
+ // pale grey that the white ink on top cannot be read against, so anchor it in the dark
89
+ // end of the ramp instead, the same trade the dark theme makes, and invert the active
90
+ // row so it still stands out. Dark mode already handles itself below.
91
+ :root.f-primary-noir:not([class*='app-dark']) .layout-modern {
92
+ --layout-modern-ink: var(--f-surface-0);
93
+ --layout-modern-canvas: linear-gradient(
94
+ 150deg,
95
+ var(--f-surface-700) 0%,
96
+ var(--f-surface-800) 45%,
97
+ var(--f-surface-900) 100%
98
+ );
99
+ --layout-modern-item-active: var(--f-surface-0);
100
+ --layout-modern-item-active-color: var(--f-surface-900);
101
+ }
102
+
103
+ :root[class*='app-dark'] .layout-modern {
104
+ --layout-modern-ink: var(--f-surface-0);
105
+ --layout-modern-canvas: linear-gradient(
106
+ 150deg,
107
+ var(--f-surface-800) 0%,
108
+ var(--f-surface-900) 45%,
109
+ var(--f-surface-950) 100%
110
+ );
111
+ --layout-modern-item-active: var(--f-primary-color);
112
+ --layout-modern-item-active-color: var(--f-primary-contrast-color);
113
+ --layout-modern-shadow: 0 18px 46px -22px rgb(0 0 0 / 80%);
114
+ }
@@ -0,0 +1,7 @@
1
+ @use './variables';
2
+ @use './shell';
3
+ @use './sidebar';
4
+ @use './menu';
5
+ @use './topbar';
6
+ @use './responsive';
7
+ @use './rtl';