Skip to content

Commit 5b57327

Browse files
AppFrame: “Enterprise Nav” phase 1.5 updates (HDS-3612) (#2299)
Co-authored-by: Cristiano Rastelli <cristiano.rastelli@hashicorp.com>
1 parent 1498b44 commit 5b57327

File tree

20 files changed

+477
-108
lines changed

20 files changed

+477
-108
lines changed

.changeset/rich-actors-speak.md

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
"@hashicorp/design-system-components": minor
3+
---
4+
5+
`AppFrame`:
6+
- Modified sticky/fixed position to turn off when viewport height is under 480px in height
7+
- Refactored styles to make `AppFrame` responsible for sticky/fixed layout of `SideNav` and `AppHeader`
8+
9+
`AppHeader`:
10+
- Styled inoperable actions as disabled (which occurs when the `SideNav` is expanded in mobile view)
11+
12+
`SideNav`:
13+
- Removed the `withAppHeader` option as it is no longer needed.

packages/components/src/components/hds/app-frame/index.hbs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
Copyright (c) HashiCorp, Inc.
33
SPDX-License-Identifier: MPL-2.0
44
}}
5-
<div class="hds-app-frame" ...attributes>
5+
<div class={{this.classNames}} ...attributes>
66
{{#if this.hasHeader}}
77
{{yield (hash Header=(component "hds/app-frame/parts/header"))}}
88
{{/if}}

packages/components/src/components/hds/app-frame/index.ts

+15-28
Original file line numberDiff line numberDiff line change
@@ -33,47 +33,34 @@ export interface HdsAppFrameSignature {
3333
}
3434

3535
export default class HdsAppFrameComponent extends Component<HdsAppFrameSignature> {
36-
/**
37-
* Indicates if the "header" container should be displayed
38-
*
39-
* @param hasHeader
40-
* @type {boolean}
41-
* @default true
42-
*/
36+
// Indicates if the "header" container should be displayed
4337
get hasHeader(): boolean {
4438
return this.args.hasHeader ?? true;
4539
}
4640

47-
/**
48-
* Indicates if the "sidebar" container should be displayed
49-
*
50-
* @param hasSidebar
51-
* @type {boolean}
52-
* @default true
53-
*/
41+
// Indicates if the "sidebar" container should be displayed
5442
get hasSidebar(): boolean {
5543
return this.args.hasSidebar ?? true;
5644
}
5745

58-
/**
59-
* Indicates if the "footer" container should be displayed
60-
*
61-
* @param hasFooter
62-
* @type {boolean}
63-
* @default true
64-
*/
46+
// Indicates if the "footer" container should be displayed
6547
get hasFooter(): boolean {
6648
return this.args.hasFooter ?? true;
6749
}
6850

69-
/**
70-
* Indicates if the "modals" container should be displayed
71-
*
72-
* @param hasModals
73-
* @type {boolean}
74-
* @default true
75-
*/
51+
// Indicates if the "modals" container should be displayed
7652
get hasModals(): boolean {
7753
return this.args.hasModals ?? true;
7854
}
55+
56+
// Get the class names to apply to the component.
57+
get classNames(): string {
58+
const classes = ['hds-app-frame'];
59+
60+
if (this.hasHeader && this.hasSidebar) {
61+
classes.push('hds-app-frame--has-header-with-sidebar');
62+
}
63+
64+
return classes.join(' ');
65+
}
7966
}

packages/components/src/components/hds/side-nav/index.ts

-6
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ interface HdsSideNavSignature {
2727
onToggleMinimizedStatus?: (arg: boolean) => void;
2828
// eslint-disable-next-line @typescript-eslint/no-explicit-any
2929
onDesktopViewportChange?: (arg: boolean) => void;
30-
withAppHeader?: boolean;
3130
};
3231
Blocks: {
3332
header?: [
@@ -146,11 +145,6 @@ export default class HdsSideNavComponent extends Component<HdsSideNavSignature>
146145
classes.push('hds-side-nav--is-animating');
147146
}
148147

149-
// Add class based on the presence of app-header
150-
if (this.args.withAppHeader) {
151-
classes.push('hds-side-nav--with-app-header');
152-
}
153-
154148
return classes.join(' ');
155149
}
156150

packages/components/src/styles/components/app-frame.scss

+17-11
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,16 @@
1616
grid-template-rows: auto 1fr auto;
1717
grid-template-columns: auto 1fr;
1818
min-height: 100vh;
19-
20-
// prevent interaction with AppHeader when SideNav is open/expanded
21-
&:has(.hds-side-nav--is-not-minimized) .hds-app-header--is-mobile {
22-
pointer-events: none;
23-
}
2419
}
2520

26-
2721
// FRAME'S CONTAINERS
2822

2923
.hds-app-frame__header {
30-
z-index: 7;
24+
z-index: 21; // needs to stay above the main content & sidebar
3125
grid-area: header;
3226

33-
// NOTE: May not need to qualify this with .hds-app-header as it may not matter if AppHeader is not present
34-
&:has(.hds-app-header) {
27+
// Make header position sticky/fixed if the viewport height is greater than 480px
28+
@media (height >= 480px) {
3529
position: sticky;
3630
top: 0;
3731
right: 0;
@@ -40,8 +34,21 @@
4034
}
4135

4236
.hds-app-frame__sidebar {
43-
z-index: 6;
37+
position: sticky;
38+
top: 0;
39+
z-index: 20; // needs to stay above the main content
4440
grid-area: sidebar;
41+
height: 100vh;
42+
min-height: 100vh;
43+
44+
// Modify sidenav layout when used together with fixed app-header
45+
@media (height >= 480px) {
46+
.hds-app-frame--has-header-with-sidebar & {
47+
top: var(--token-app-header-height);
48+
height: calc(100vh - var(--token-app-header-height));
49+
min-height: calc(100vh - var(--token-app-header-height));
50+
}
51+
}
4552
}
4653

4754
.hds-app-frame__main {
@@ -52,7 +59,6 @@
5259
grid-area: footer;
5360
}
5461

55-
5662
// MODALS "CONTAINER"
5763

5864
.hds-app-frame__modals {

packages/components/src/styles/components/app-header.scss

+37-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414
.hds-app-header {
1515
position: relative;
16-
z-index: 20; // needs to stay above the main content
1716
display: flex;
1817
gap: 12px;
1918
align-items: center;
@@ -76,6 +75,30 @@
7675
.hds-dropdown-toggle-button,
7776
.hds-dropdown-toggle-icon {
7877
@include hds-interactive-dark-theme();
78+
79+
// disabled state:
80+
&:disabled,
81+
&[disabled],
82+
&.mock-disabled,
83+
&:disabled:focus,
84+
&[disabled]:focus,
85+
&.mock-disabled:focus,
86+
&:disabled:hover,
87+
&[disabled]:hover,
88+
&.mock-disabled:hover {
89+
@include hds-interactive-dark-theme-state-disabled();
90+
}
91+
}
92+
}
93+
94+
// prevent interaction with AppHeader when SideNav is open/expanded
95+
.hds-app-frame:has(.hds-side-nav--is-not-minimized) .hds-app-header--is-mobile {
96+
.hds-button,
97+
.hds-dropdown-toggle-button,
98+
.hds-dropdown-toggle-icon,
99+
.hds-app-header__home-link {
100+
@include hds-interactive-dark-theme-state-disabled(); // emulate disabled state
101+
pointer-events: none;
79102
}
80103
}
81104

@@ -90,6 +113,19 @@
90113
// Set home link container size:
91114
width: var(--token-app-header-home-link-size);
92115
height: var(--token-app-header-home-link-size);
116+
117+
// disabled state:
118+
&:disabled,
119+
&[disabled],
120+
&.mock-disabled,
121+
&:disabled:focus,
122+
&[disabled]:focus,
123+
&.mock-disabled:focus,
124+
&:disabled:hover,
125+
&[disabled]:hover,
126+
&.mock-disabled:hover {
127+
@include hds-interactive-dark-theme-state-disabled();
128+
}
93129

94130
// Set SVG logo size:
95131
svg {

packages/components/src/styles/components/side-nav/header.scss

+39
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,19 @@
4747
width: 100%;
4848
height: 100%;
4949
padding: calc(var(--token-side-nav-header-home-link-padding) - 1px); // by design - we take in account the transparent border
50+
51+
// disabled state:
52+
&:disabled,
53+
&[disabled],
54+
&.mock-disabled,
55+
&:disabled:focus,
56+
&[disabled]:focus,
57+
&.mock-disabled:focus,
58+
&:disabled:hover,
59+
&[disabled]:hover,
60+
&.mock-disabled:hover {
61+
@include hds-interactive-dark-theme-state-disabled();
62+
}
5063
}
5164

5265

@@ -67,6 +80,19 @@
6780
.hds-dropdown-toggle-button,
6881
.hds-dropdown-toggle-icon {
6982
@include hds-interactive-dark-theme();
83+
84+
// disabled state:
85+
&:disabled,
86+
&[disabled],
87+
&.mock-disabled,
88+
&:disabled:focus,
89+
&[disabled]:focus,
90+
&.mock-disabled:focus,
91+
&:disabled:hover,
92+
&[disabled]:hover,
93+
&.mock-disabled:hover {
94+
@include hds-interactive-dark-theme-state-disabled();
95+
}
7096
}
7197
}
7298

@@ -81,4 +107,17 @@
81107
width: 36px; // same height as the dropdown "toggle"
82108
height: 36px;
83109
padding: 5px; // we take in account the transparent border
110+
111+
// disabled state:
112+
&:disabled,
113+
&[disabled],
114+
&.mock-disabled,
115+
&:disabled:focus,
116+
&[disabled]:focus,
117+
&.mock-disabled:focus,
118+
&:disabled:hover,
119+
&[disabled]:hover,
120+
&.mock-disabled:hover {
121+
@include hds-interactive-dark-theme-state-disabled();
122+
}
84123
}

packages/components/src/styles/components/side-nav/main.scss

+3-14
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,14 @@
88
//
99

1010
.hds-side-nav {
11-
position: sticky;
12-
top: 0;
13-
z-index: 20; // needs to stay above the main content
11+
position: relative;
1412
width: var(--hds-app-sidenav-width-fixed); // "default" width used by the `SideNav::Base` subcomponent (that is not responsive)
15-
height: 100vh;
16-
min-height: 100vh;
13+
height: 100%;
14+
min-height: 100%;
1715
isolation: isolate; // used to create a new stacking context (so we can set the overlay's z-index to -1)
1816

1917
// VARIATIONS
2018

21-
// with-app-header
22-
// Modify sidenav layout when used together with app-header
23-
24-
&.hds-side-nav--with-app-header {
25-
top: var(--token-app-header-height);
26-
height: calc(100vh - var(--token-app-header-height));
27-
min-height: calc(100vh - var(--token-app-header-height));
28-
}
29-
3019
// headerless
3120
// SideNav without a :header block
3221
&.hds-side-nav--is-headerless {

packages/components/src/styles/mixins/_interactive-dark-theme.scss

+5-14
Original file line numberDiff line numberDiff line change
@@ -88,19 +88,10 @@
8888
border-color: var(--token-color-palette-neutral-400);
8989
}
9090
}
91+
}
9192

92-
// Disabled:
93-
&:disabled,
94-
&[disabled],
95-
&.mock-disabled,
96-
&:disabled:focus,
97-
&[disabled]:focus,
98-
&.mock-disabled:focus,
99-
&:disabled:hover,
100-
&[disabled]:hover,
101-
&.mock-disabled:hover {
102-
color: var(--token-color-foreground-disabled);
103-
background-color: var(--token-color-palette-neutral-600);
104-
border-color: var(--token-color-palette-neutral-500);
105-
}
93+
@mixin hds-interactive-dark-theme-state-disabled() {
94+
color: var(--token-color-foreground-disabled);
95+
background-color: var(--token-color-palette-neutral-600);
96+
border-color: var(--token-color-palette-neutral-500);
10697
}

showcase/app/styles/showcase-pages/app-frame.scss

+12
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,18 @@ body.layouts-app-frame {
6666
width: 100%;
6767
height: 100%;
6868
}
69+
70+
// remove sticky positioning from examples
71+
.hds-app-frame__header,
72+
.hds-app-frame__sidebar {
73+
position: relative;
74+
top: 0;
75+
}
76+
77+
.hds-app-frame__sidebar {
78+
height: auto;
79+
min-height: 0;
80+
}
6981
}
7082

7183
.shw-layout-app-frame-wrapper--with-3d {

showcase/app/templates/components/app-header.hbs

+4-4
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@
312312
<Shw::Text::H4>States</Shw::Text::H4>
313313

314314
<Shw::Flex as |SF|>
315-
{{#let (array "default" "hover" "active" "focus") as |states|}}
315+
{{#let (array "default" "hover" "active" "focus" "disabled") as |states|}}
316316
{{#each states as |state|}}
317317
<SF.Item @label={{state}}>
318318
<div class="hds-app-header">
@@ -324,7 +324,7 @@
324324
</Shw::Flex>
325325

326326
<Shw::Flex as |SF|>
327-
{{#let (array "default" "hover" "active" "focus") as |states|}}
327+
{{#let (array "default" "hover" "active" "focus" "disabled") as |states|}}
328328
{{#each states as |state|}}
329329
<SF.Item>
330330
<div class="hds-app-header">
@@ -349,7 +349,7 @@
349349

350350
<Shw::Text::Body>Secondary</Shw::Text::Body>
351351
<Shw::Flex as |SF|>
352-
{{#let (array "default" "hover" "active" "focus") as |states|}}
352+
{{#let (array "default" "hover" "active" "focus" "disabled") as |states|}}
353353
{{#each states as |state|}}
354354
<SF.Item @label={{state}}>
355355
<div class="hds-app-header">
@@ -368,7 +368,7 @@
368368

369369
<Shw::Text::Body>Primary</Shw::Text::Body>
370370
<Shw::Flex as |SF|>
371-
{{#let (array "default" "hover" "active" "focus") as |states|}}
371+
{{#let (array "default" "hover" "active" "focus" "disabled") as |states|}}
372372
{{#each states as |state|}}
373373
<SF.Item @label={{state}}>
374374

0 commit comments

Comments
 (0)