@hashicorp/design-system-components 2.0.0 → 2.2.0
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.
- package/CHANGELOG.md +72 -20
- package/HOW-TO-TEST-A-COMPONENT-IN-CLOUD-UI.md +28 -3
- package/addon/components/hds/app-frame/index.hbs +24 -0
- package/addon/components/hds/app-frame/index.js +52 -0
- package/addon/components/hds/app-frame/parts/footer.hbs +7 -0
- package/addon/components/hds/{empty-state → app-frame/parts}/header.hbs +2 -2
- package/addon/components/hds/{empty-state/body.hbs → app-frame/parts/main.hbs} +2 -2
- package/addon/components/hds/app-frame/parts/modals.hbs +6 -0
- package/addon/components/hds/{empty-state/footer.hbs → app-frame/parts/sidebar.hbs} +2 -2
- package/addon/components/hds/application-state/body.hbs +13 -0
- package/addon/components/hds/application-state/footer.hbs +7 -0
- package/addon/components/hds/application-state/footer.js +35 -0
- package/addon/components/hds/application-state/header.hbs +20 -0
- package/addon/components/hds/application-state/index.hbs +13 -0
- package/addon/components/hds/dropdown/footer.hbs +5 -0
- package/addon/components/hds/dropdown/header.hbs +5 -0
- package/addon/components/hds/dropdown/index.hbs +2 -2
- package/addon/components/hds/dropdown/index.js +18 -2
- package/addon/components/hds/dropdown/list-item/checkbox.hbs +5 -0
- package/addon/components/hds/dropdown/list-item/checkbox.js +5 -0
- package/addon/components/hds/dropdown/list-item/checkmark.hbs +5 -0
- package/addon/components/hds/dropdown/list-item/checkmark.js +5 -0
- package/addon/components/hds/dropdown/list-item/radio.hbs +5 -0
- package/addon/components/hds/dropdown/list-item/radio.js +5 -0
- package/addon/components/hds/dropdown/toggle/chevron.hbs +5 -0
- package/addon/components/hds/flyout/footer.hbs +7 -0
- package/addon/components/hds/flyout/index.hbs +1 -0
- package/addon/components/hds/side-nav/base.hbs +14 -0
- package/addon/components/hds/side-nav/{home-link.js → header/home-link.js} +2 -2
- package/addon/components/hds/side-nav/{icon-button.hbs → header/icon-button.hbs} +1 -1
- package/addon/components/hds/side-nav/{icon-button.js → header/icon-button.js} +2 -2
- package/addon/components/hds/side-nav/{header.hbs → header/index.hbs} +2 -2
- package/addon/components/hds/side-nav/index.hbs +40 -0
- package/addon/components/hds/side-nav/index.js +107 -0
- package/addon/components/hds/side-nav/list/index.hbs +2 -0
- package/addon/components/hds/side-nav/portal/index.hbs +12 -0
- package/addon/components/hds/side-nav/portal/target.hbs +14 -0
- package/addon/components/hds/side-nav/portal/target.js +156 -0
- package/app/components/hds/{empty-state/body.js → app-frame/index.js} +1 -1
- package/app/components/hds/app-frame/parts/footer.js +6 -0
- package/app/components/hds/app-frame/parts/header.js +6 -0
- package/app/components/hds/{empty-state/footer.js → app-frame/parts/main.js} +1 -1
- package/app/components/hds/app-frame/parts/modals.js +6 -0
- package/app/components/hds/app-frame/parts/sidebar.js +6 -0
- package/app/components/hds/application-state/body.js +6 -0
- package/app/components/hds/application-state/footer.js +6 -0
- package/app/components/hds/application-state/header.js +6 -0
- package/app/components/hds/application-state/index.js +6 -0
- package/app/components/hds/dropdown/footer.js +5 -0
- package/app/components/hds/dropdown/header.js +5 -0
- package/app/components/hds/dropdown/list-item/checkbox.js +5 -0
- package/app/components/hds/dropdown/list-item/checkmark.js +5 -0
- package/app/components/hds/dropdown/list-item/radio.js +5 -0
- package/app/components/hds/{side-nav/wrapper.js → flyout/footer.js} +1 -1
- package/app/components/hds/side-nav/base.js +6 -0
- package/app/components/hds/side-nav/{home-link.js → header/home-link.js} +1 -1
- package/app/components/hds/side-nav/{icon-button.js → header/icon-button.js} +1 -1
- package/app/components/hds/{empty-state → side-nav}/index.js +1 -1
- package/app/components/hds/{empty-state/header.js → side-nav/portal/index.js} +1 -1
- package/app/components/hds/side-nav/portal/target.js +6 -0
- package/app/styles/@hashicorp/design-system-components.scss +2 -1
- package/app/styles/@hashicorp/design-system-power-select-overrides.scss +33 -3
- package/app/styles/components/app-frame.scss +60 -0
- package/app/styles/components/application-state.scss +55 -0
- package/app/styles/components/dropdown.scss +11 -0
- package/app/styles/components/flyout.scss +15 -1
- package/app/styles/components/form/checkbox.scss +1 -1
- package/app/styles/components/form/radio.scss +1 -1
- package/app/styles/components/form/text-input.scss +1 -1
- package/app/styles/components/form/textarea.scss +2 -1
- package/app/styles/components/side-nav/a11y-refocus.scss +30 -0
- package/app/styles/components/side-nav/content.scss +156 -0
- package/app/styles/components/side-nav/header.scss +102 -0
- package/app/styles/components/side-nav/index.scss +10 -0
- package/app/styles/components/side-nav/main.scss +202 -0
- package/app/styles/components/side-nav/vars.scss +36 -0
- package/blueprints/hds-component-test/files/tests/integration/components/hds/__name__/index-test.js +14 -11
- package/package.json +6 -4
- package/addon/components/hds/empty-state/index.hbs +0 -13
- package/addon/components/hds/side-nav/wrapper.hbs +0 -18
- package/app/styles/components/empty-state.scss +0 -37
- package/app/styles/components/side-nav.scss +0 -275
- /package/addon/components/hds/side-nav/{home-link.hbs → header/home-link.hbs} +0 -0
- /package/app/components/hds/side-nav/{header.js → header/index.js} +0 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) HashiCorp, Inc.
|
|
3
|
+
* SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
//
|
|
7
|
+
// APPLICATION-STATE COMPONENT
|
|
8
|
+
//
|
|
9
|
+
|
|
10
|
+
$hds-application-state-padding: 12px 0;
|
|
11
|
+
|
|
12
|
+
.hds-application-state {
|
|
13
|
+
width: 19.5rem;
|
|
14
|
+
max-width: 100%;
|
|
15
|
+
margin: 0 auto; // this will center the component in the parent container
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.hds-application-state__header {
|
|
19
|
+
display: grid;
|
|
20
|
+
grid-template-columns: min-content 1fr;
|
|
21
|
+
align-items: start;
|
|
22
|
+
color: var(--token-color-foreground-faint);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.hds-application-state__icon {
|
|
26
|
+
margin-right: 8px; // instead of column gap
|
|
27
|
+
padding-top: 4px; // this seems to align the icon along with line 21
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.hds-application-state__title,
|
|
31
|
+
.hds-application-state__error-code {
|
|
32
|
+
grid-column-start: 2;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.hds-application-state__body {
|
|
36
|
+
display: flex;
|
|
37
|
+
padding: $hds-application-state-padding;
|
|
38
|
+
color: var(--token-color-foreground-faint);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.hds-application-state__footer {
|
|
42
|
+
display: flex;
|
|
43
|
+
justify-content: space-between;
|
|
44
|
+
|
|
45
|
+
&.hds-application-state__footer--has-divider {
|
|
46
|
+
padding: $hds-application-state-padding;
|
|
47
|
+
border-top: 1px solid var(--token-color-border-strong);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// in case users do something outside design guidelines
|
|
51
|
+
.hds-link-standalone + .hds-link-standalone {
|
|
52
|
+
margin-left: 8px;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
@@ -14,6 +14,17 @@
|
|
|
14
14
|
|
|
15
15
|
$hds-dropdown-toggle-border-radius: $hds-button-border-radius;
|
|
16
16
|
|
|
17
|
+
// DROPDOWN
|
|
18
|
+
|
|
19
|
+
.hds-dropdown--is-inline {
|
|
20
|
+
display: inline-block;
|
|
21
|
+
|
|
22
|
+
.hds-dropdown-toggle-icon,
|
|
23
|
+
.hds-dropdown-toggle-button {
|
|
24
|
+
display: inline-flex;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
17
28
|
// TOGGLE/ICON
|
|
18
29
|
|
|
19
30
|
.hds-dropdown-toggle-icon {
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
right: 0;
|
|
46
46
|
bottom: 0;
|
|
47
47
|
left: 0;
|
|
48
|
-
z-index:
|
|
48
|
+
z-index: 49;
|
|
49
49
|
background: var(--token-color-palette-neutral-700);
|
|
50
50
|
opacity: 0.5;
|
|
51
51
|
}
|
|
@@ -91,6 +91,20 @@
|
|
|
91
91
|
border-top: 1px solid var(--token-color-border-primary);
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
.hds-flyout__footer {
|
|
95
|
+
flex: none;
|
|
96
|
+
padding: 16px 24px;
|
|
97
|
+
background: var(--token-color-surface-faint);
|
|
98
|
+
border-top: 1px solid var(--token-color-border-primary);
|
|
99
|
+
|
|
100
|
+
// Tertiary buttons must always be placed/aligned at the end of the row
|
|
101
|
+
.hds-button-set {
|
|
102
|
+
.hds-button--color-tertiary {
|
|
103
|
+
margin-left: auto;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
94
108
|
.hds-flyout--size-medium {
|
|
95
109
|
@include hds-flyout-position(480px);
|
|
96
110
|
}
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
&:not(:checked, :indeterminate) {
|
|
31
31
|
background-color: var(--token-form-control-base-surface-color-default);
|
|
32
32
|
border-color: var(--token-form-control-base-border-color-default);
|
|
33
|
-
box-shadow: var(--
|
|
33
|
+
box-shadow: var(--token-elevation-inset-box-shadow);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
&:checked {
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
&:not(:checked) {
|
|
31
31
|
background-color: var(--token-form-control-base-surface-color-default);
|
|
32
32
|
border-color: var(--token-form-control-base-border-color-default);
|
|
33
|
-
box-shadow: var(--
|
|
33
|
+
box-shadow: var(--token-elevation-inset-box-shadow);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
&:checked {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
background-color: var(--token-form-control-base-surface-color-default);
|
|
19
19
|
border: var(--token-form-control-border-width) solid var(--token-form-control-base-border-color-default);
|
|
20
20
|
border-radius: var(--token-form-control-border-radius);
|
|
21
|
-
box-shadow: var(--
|
|
21
|
+
box-shadow: var(--token-elevation-inset-box-shadow);
|
|
22
22
|
|
|
23
23
|
// PLACEHOLDER
|
|
24
24
|
|
|
@@ -13,12 +13,13 @@
|
|
|
13
13
|
.hds-form-textarea {
|
|
14
14
|
width: 100%;
|
|
15
15
|
max-width: 100%;
|
|
16
|
+
min-height: 36px;
|
|
16
17
|
padding: var(--token-form-control-padding);
|
|
17
18
|
color: var(--token-form-control-base-foreground-value-color);
|
|
18
19
|
background-color: var(--token-form-control-base-surface-color-default);
|
|
19
20
|
border: var(--token-form-control-border-width) solid var(--token-form-control-base-border-color-default);
|
|
20
21
|
border-radius: var(--token-form-control-border-radius);
|
|
21
|
-
box-shadow: var(--
|
|
22
|
+
box-shadow: var(--token-elevation-inset-box-shadow);
|
|
22
23
|
resize: vertical;
|
|
23
24
|
|
|
24
25
|
// PLACEHOLDER
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) HashiCorp, Inc.
|
|
3
|
+
* SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
//
|
|
7
|
+
// SIDE-NAV > A11Y-REFOCUS "SKIP LINK"
|
|
8
|
+
//
|
|
9
|
+
|
|
10
|
+
.hds-side-nav { // this extra qualifier is needed to increase specificity of the selector, please don't remove it
|
|
11
|
+
.ember-a11y-refocus-skip-link {
|
|
12
|
+
top: 10px;
|
|
13
|
+
left: 10px;
|
|
14
|
+
z-index: 20;
|
|
15
|
+
width: max-content;
|
|
16
|
+
padding: 2px 10px 4px;
|
|
17
|
+
color: var(--token-color-foreground-action);
|
|
18
|
+
font-size: var(--token-typography-display-200-font-size);
|
|
19
|
+
font-family: var(--token-typography-display-200-font-family);
|
|
20
|
+
line-height: var(--token-typography-display-200-line-height);
|
|
21
|
+
background-color: var(--token-color-surface-faint);
|
|
22
|
+
border-radius: 3px;
|
|
23
|
+
transform: translateY(-200%);
|
|
24
|
+
transition: 0.6s ease-in-out;
|
|
25
|
+
|
|
26
|
+
&:focus {
|
|
27
|
+
transform: translateY(0);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) HashiCorp, Inc.
|
|
3
|
+
* SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
//
|
|
7
|
+
// SIDE-NAV > CONTENT (PORTALS + LISTS OF ITEMS/LINKS)
|
|
8
|
+
//
|
|
9
|
+
|
|
10
|
+
@use "../../mixins/focus-ring" as *;
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
// PANELS (wrappers used in conjunction with the portal elements)
|
|
14
|
+
|
|
15
|
+
.hds-side-nav__content {
|
|
16
|
+
// we use this trick (increasing the container size here, and reducing it at single panel level)
|
|
17
|
+
// to have the panels width match the sidebar extended width (it's used in the animated sliding of the panels)
|
|
18
|
+
margin: 0 calc(var(--token-side-nav-wrapper-padding-horizontal) * -1);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.hds-side-nav__content-panels {
|
|
22
|
+
// see https://codepen.io/didoo/pen/YzOeRPr
|
|
23
|
+
display: grid;
|
|
24
|
+
grid-template-columns: repeat(5, 100%);
|
|
25
|
+
width: 100%;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.hds-side-nav__content-panel {
|
|
29
|
+
padding: 0 var(--token-side-nav-wrapper-padding-horizontal);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// (LIST) TITLE
|
|
33
|
+
|
|
34
|
+
.hds-side-nav__list-title {
|
|
35
|
+
display: flex;
|
|
36
|
+
align-items: center;
|
|
37
|
+
min-height: 34px;
|
|
38
|
+
margin-top: var(--token-side-nav-body-list-margin-vertical);
|
|
39
|
+
padding: 0 var(--token-side-nav-body-list-item-padding-horizontal);
|
|
40
|
+
color: var(--token-side-nav-color-foreground-faint);
|
|
41
|
+
|
|
42
|
+
// Remove margin from title at top of all list-items & lists
|
|
43
|
+
.hds-side-nav__list-wrapper:first-child .hds-side-nav__list-item:first-child > & {
|
|
44
|
+
margin-top: 0;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
// LIST (root elements)
|
|
50
|
+
|
|
51
|
+
.hds-side-nav__list-wrapper, // <nav> element
|
|
52
|
+
.hds-side-nav__list { // <ul> element
|
|
53
|
+
margin: 0;
|
|
54
|
+
padding: 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
// ITEM (generic container)
|
|
59
|
+
|
|
60
|
+
.hds-side-nav__list-item { // <li> element
|
|
61
|
+
list-style-type: none;
|
|
62
|
+
|
|
63
|
+
& + & {
|
|
64
|
+
margin-top: var(--token-side-nav-body-list-item-spacing-vertical);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.hds-side-nav__list-item-link { // <a>/<button> element (via Hds::Interactive)
|
|
69
|
+
display: flex;
|
|
70
|
+
align-items: center;
|
|
71
|
+
width: 100%;
|
|
72
|
+
min-height: var(--token-side-nav-body-list-item-height);
|
|
73
|
+
padding: var(--token-side-nav-body-list-item-padding-vertical) var(--token-side-nav-body-list-item-padding-horizontal);
|
|
74
|
+
color: var(--token-side-nav-color-foreground-primary);
|
|
75
|
+
text-decoration: none;
|
|
76
|
+
background: var(--token-side-nav-color-surface-primary);
|
|
77
|
+
// "Link" could render as an HTML button element so this overrides the default border style in that case:
|
|
78
|
+
border-color: transparent;
|
|
79
|
+
border-radius: var(--token-side-nav-body-list-item-border-radius);
|
|
80
|
+
|
|
81
|
+
&:focus,
|
|
82
|
+
&.mock-focus {
|
|
83
|
+
@include hds-focus-ring-with-pseudo-element();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
&:hover,
|
|
87
|
+
&.mock-hover {
|
|
88
|
+
background: var(--token-side-nav-color-surface-interactive-hover);
|
|
89
|
+
border-color: transparent;
|
|
90
|
+
|
|
91
|
+
.hds-side-nav__list-item-text,
|
|
92
|
+
.hds-side-nav__list-item-icon-leading,
|
|
93
|
+
.hds-side-nav__list-item-icon-trailing {
|
|
94
|
+
color: var(--token-side-nav-color-foreground-strong);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// notice: this ".active" extra class is used to match the corresponding `active` class assigned automatically
|
|
99
|
+
// by the `<LinkTo>` Ember component (when the link is "current), so that consumers get it for free if they want
|
|
100
|
+
// otherwise they can use the `@isActive` argument to set this visual state directly
|
|
101
|
+
&.active,
|
|
102
|
+
&:active,
|
|
103
|
+
&.mock-active {
|
|
104
|
+
background: var(--token-side-nav-color-surface-interactive-active);
|
|
105
|
+
|
|
106
|
+
.hds-side-nav__list-item-text,
|
|
107
|
+
.hds-side-nav__list-item-icon-leading,
|
|
108
|
+
.hds-side-nav__list-item-icon-trailing {
|
|
109
|
+
color: var(--token-side-nav-color-foreground-strong);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.hds-badge,
|
|
113
|
+
.hds-badge-count {
|
|
114
|
+
color: var(--token-color-foreground-primary);
|
|
115
|
+
background: var(--token-color-surface-strong);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.hds-badge,
|
|
120
|
+
.hds-badge-count {
|
|
121
|
+
margin-left: var(--token-side-nav-body-list-item-content-spacing-horizontal);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// special override for the "back-link" element (no visible active state, by design)
|
|
126
|
+
.hds-side-nav__list-item-link--back-link {
|
|
127
|
+
&:active,
|
|
128
|
+
&.mock-active {
|
|
129
|
+
background: var(--token-side-nav-color-surface-primary);
|
|
130
|
+
|
|
131
|
+
.hds-side-nav__list-item-text,
|
|
132
|
+
.hds-side-nav__list-item-icon-leading,
|
|
133
|
+
.hds-side-nav__list-item-icon-trailing {
|
|
134
|
+
color: var(--token-side-nav-color-foreground-primary);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
// LIST ITEM > INNER ELEMENTS
|
|
141
|
+
|
|
142
|
+
.hds-side-nav__list-item-text {
|
|
143
|
+
color: var(--token-side-nav-color-foreground-primary);
|
|
144
|
+
text-align: left;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.hds-side-nav__list-item-icon-leading {
|
|
148
|
+
flex: none;
|
|
149
|
+
margin-right: var(--token-side-nav-body-list-item-content-spacing-horizontal);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.hds-side-nav__list-item-icon-trailing {
|
|
153
|
+
flex: none;
|
|
154
|
+
margin-left: auto;
|
|
155
|
+
padding-left: var(--token-side-nav-body-list-item-content-spacing-horizontal);
|
|
156
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) HashiCorp, Inc.
|
|
3
|
+
* SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
//
|
|
7
|
+
// SIDE-NAV > HEADER
|
|
8
|
+
//
|
|
9
|
+
|
|
10
|
+
@use "../../mixins/focus-ring" as *;
|
|
11
|
+
|
|
12
|
+
@mixin hds-side-nav-icon-button($add-visible-border: false) {
|
|
13
|
+
color: var(--token-side-nav-color-foreground-strong);
|
|
14
|
+
background-color: transparent;
|
|
15
|
+
border: 1px solid transparent;
|
|
16
|
+
border-radius: var(--token-side-nav-body-list-item-border-radius);
|
|
17
|
+
cursor: pointer;
|
|
18
|
+
|
|
19
|
+
@if ($add-visible-border) {
|
|
20
|
+
border-color: var(--token-color-palette-neutral-500);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
&:focus,
|
|
24
|
+
&.mock-focus {
|
|
25
|
+
@include hds-focus-ring-with-pseudo-element($top: -1px, $right: -1px, $bottom: -1px, $left: -1px);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
&:hover,
|
|
29
|
+
&.mock-hover {
|
|
30
|
+
color: var(--token-side-nav-color-foreground-strong); // to avoid overrides by specificity (eg. `a:hover`)
|
|
31
|
+
background: var(--token-side-nav-color-surface-interactive-hover);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
&:active,
|
|
35
|
+
&.mock-active {
|
|
36
|
+
color: var(--token-side-nav-color-foreground-strong); // to avoid overrides by specificity (eg. `a:hover`)
|
|
37
|
+
background: var(--token-side-nav-color-surface-interactive-active);
|
|
38
|
+
|
|
39
|
+
@if ($add-visible-border) {
|
|
40
|
+
border-color: var(--token-color-palette-neutral-400);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// HEADER (LAYOUT WRAPPER)
|
|
46
|
+
|
|
47
|
+
.hds-side-nav-header {
|
|
48
|
+
display: flex;
|
|
49
|
+
align-items: center;
|
|
50
|
+
justify-content: space-between;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
// LOGO
|
|
55
|
+
|
|
56
|
+
.hds-side-nav-header__logo-container {
|
|
57
|
+
display: flex;
|
|
58
|
+
flex: none;
|
|
59
|
+
align-items: center;
|
|
60
|
+
justify-content: center;
|
|
61
|
+
width: var(--token-side-nav-header-home-link-logo-size);
|
|
62
|
+
height: var(--token-side-nav-header-home-link-logo-size);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// "home-link"
|
|
66
|
+
|
|
67
|
+
.hds-side-nav__home-link {
|
|
68
|
+
@include hds-side-nav-icon-button();
|
|
69
|
+
display: block;
|
|
70
|
+
width: 100%;
|
|
71
|
+
height: 100%;
|
|
72
|
+
padding: calc(var(--token-side-nav-header-home-link-padding) - 1px); // by design - we take in account the transparent border
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
// ACTIONS
|
|
77
|
+
|
|
78
|
+
.hds-side-nav-header__actions-container {
|
|
79
|
+
display: flex;
|
|
80
|
+
|
|
81
|
+
> * + * { margin-left: var(--token-side-nav-header-actions-spacing); }
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// dropdown overrides
|
|
85
|
+
|
|
86
|
+
.hds-side-nav__dropdown { // ⬅︎ add this class name to the `Hds::Dropdown` component to apply the style overrides
|
|
87
|
+
.hds-dropdown-toggle-icon {
|
|
88
|
+
@include hds-side-nav-icon-button($add-visible-border: true);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// generic "icon-button"
|
|
93
|
+
|
|
94
|
+
.hds-side-nav__icon-button {
|
|
95
|
+
@include hds-side-nav-icon-button($add-visible-border: true);
|
|
96
|
+
display: flex;
|
|
97
|
+
align-items: center;
|
|
98
|
+
justify-content: center;
|
|
99
|
+
width: 36px; // same height as the dropdown "toggle"
|
|
100
|
+
height: 36px;
|
|
101
|
+
padding: 5px; // we take in account the transparent border
|
|
102
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) HashiCorp, Inc.
|
|
3
|
+
* SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
//
|
|
7
|
+
// SIDE-NAV
|
|
8
|
+
//
|
|
9
|
+
|
|
10
|
+
.hds-side-nav {
|
|
11
|
+
position: sticky;
|
|
12
|
+
top: 0;
|
|
13
|
+
z-index: 20; // needs to stay above the main content
|
|
14
|
+
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;
|
|
17
|
+
isolation: isolate; // used to create a new stacking context (so we can set the overlay's z-index to -1)
|
|
18
|
+
|
|
19
|
+
// RESPONSIVENESS - This controls the width of the top-level container ("sidebar") in the grid, and impacts the available space for the "main" grid area
|
|
20
|
+
|
|
21
|
+
&.hds-side-nav--is-responsive {
|
|
22
|
+
transition:
|
|
23
|
+
width var(--hds-app-sidenav-animation-duration)
|
|
24
|
+
var(--hds-app-sidenav-animation-easing);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// mobile
|
|
28
|
+
&.hds-side-nav--is-mobile {
|
|
29
|
+
width: var(--hds-app-sidenav-width-minimized);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// desktop
|
|
33
|
+
&.hds-side-nav--is-desktop {
|
|
34
|
+
width: var(--hds-app-sidenav-width-expanded);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
// OVERLAY
|
|
40
|
+
|
|
41
|
+
.hds-side-nav__overlay {
|
|
42
|
+
position: fixed;
|
|
43
|
+
z-index: -1;
|
|
44
|
+
inset: 0;
|
|
45
|
+
background-color: var(--token-color-palette-neutral-700);
|
|
46
|
+
opacity: 0.2;
|
|
47
|
+
transition:
|
|
48
|
+
opacity var(--hds-app-sidenav-animation-duration)
|
|
49
|
+
var(--hds-app-sidenav-animation-easing)
|
|
50
|
+
var(--hds-app-sidenav-animation-delay);
|
|
51
|
+
|
|
52
|
+
// when we're minimized (mobile) we don't want the overlay to be visible/interactive
|
|
53
|
+
.hds-side-nav--is-minimized & {
|
|
54
|
+
opacity: 0;
|
|
55
|
+
pointer-events: none;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// when it's desktop we _never_ want the overlay to be visible
|
|
59
|
+
.hds-side-nav--is-desktop & {
|
|
60
|
+
display: none;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
// MENU/TOGGLE BUTTON
|
|
66
|
+
|
|
67
|
+
.hds-side-nav__menu-toggle-button {
|
|
68
|
+
position: absolute;
|
|
69
|
+
z-index: 1;
|
|
70
|
+
color: var(--token-color-foreground-high-contrast);
|
|
71
|
+
background: none;
|
|
72
|
+
border: 1px solid transparent;
|
|
73
|
+
cursor: pointer;
|
|
74
|
+
transition-timing-function: var(--hds-app-sidenav-animation-easing);
|
|
75
|
+
transition-duration: var(--hds-app-sidenav-animation-duration);
|
|
76
|
+
transition-property: width, height, padding, border-radius, transform;
|
|
77
|
+
|
|
78
|
+
&:hover {
|
|
79
|
+
background-color: var(--token-color-palette-neutral-600);
|
|
80
|
+
border-color: transparent;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
&:active {
|
|
84
|
+
background-color: var(--token-color-palette-neutral-500);
|
|
85
|
+
border-color: transparent;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
&:focus {
|
|
89
|
+
background-color: var(--token-color-palette-neutral-500);
|
|
90
|
+
border-color: var(--token-color-focus-action-internal);
|
|
91
|
+
outline: 3px solid var(--token-color-focus-action-external);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// by default it's styled as "close" button
|
|
95
|
+
.hds-side-nav--is-mobile & {
|
|
96
|
+
width: 24px;
|
|
97
|
+
height: 24px;
|
|
98
|
+
padding: 1px;
|
|
99
|
+
background-color: var(--token-color-foreground-primary);
|
|
100
|
+
border-radius: 3px;
|
|
101
|
+
transform:
|
|
102
|
+
translateX(calc(var(--hds-app-sidenav-width-expanded) + 8px))
|
|
103
|
+
translateY(24px);
|
|
104
|
+
// z-index: 15; // not needed anymore?
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// when the sidenav is minimized it's styled as "menu" button
|
|
108
|
+
.hds-side-nav--is-mobile.hds-side-nav--is-minimized & {
|
|
109
|
+
width: 36px;
|
|
110
|
+
height: 36px;
|
|
111
|
+
padding: 5px;
|
|
112
|
+
border-radius: 5px;
|
|
113
|
+
transform: translateX(22px) translateY(var(--hds-app-sidenav-menu-button-y-shift));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// when it's desktop we _never_ want to show the menu/toggle button
|
|
117
|
+
.hds-side-nav--is-desktop & {
|
|
118
|
+
display: none;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
// RESPONSIVE WRAPPER
|
|
124
|
+
// this container element is used to control the width of the sidebar at different viewports (desktop/mobile) and states (minimized/expanded)
|
|
125
|
+
|
|
126
|
+
.hds-side-nav__wrapper {
|
|
127
|
+
display: flex;
|
|
128
|
+
flex-direction: column;
|
|
129
|
+
height: 100%;
|
|
130
|
+
color: var(--token-side-nav-color-foreground-primary); // we set a default color (in case generic content is added to the header/body/footer of the sidenav)
|
|
131
|
+
background: var(--token-side-nav-color-surface-primary);
|
|
132
|
+
|
|
133
|
+
// RESPONSIVENESS - This controls the width of the "sidenav" container, and is independent (bur related) from the parent "sidebar" grid area
|
|
134
|
+
|
|
135
|
+
.hds-side-nav--is-responsive & {
|
|
136
|
+
transition:
|
|
137
|
+
width var(--hds-app-sidenav-animation-duration)
|
|
138
|
+
var(--hds-app-sidenav-animation-easing);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// mobile
|
|
142
|
+
.hds-side-nav--is-mobile.hds-side-nav--is-minimized & {
|
|
143
|
+
width: var(--hds-app-sidenav-width-minimized);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.hds-side-nav--is-mobile.hds-side-nav--is-not-minimized & {
|
|
147
|
+
width: var(--hds-app-sidenav-width-expanded);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// desktop
|
|
151
|
+
.hds-side-nav--is-desktop & {
|
|
152
|
+
width: var(--hds-app-sidenav-width-expanded);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// wrapper's child "containers"
|
|
157
|
+
|
|
158
|
+
.hds-side-nav__wrapper-header {
|
|
159
|
+
padding-top: var(--token-side-nav-wrapper-padding-vertical);
|
|
160
|
+
padding-right: var(--token-side-nav-wrapper-padding-horizontal);
|
|
161
|
+
padding-bottom: 8px; // by design
|
|
162
|
+
padding-left: var(--token-side-nav-wrapper-padding-horizontal);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.hds-side-nav__wrapper-body {
|
|
166
|
+
flex: 1;
|
|
167
|
+
padding:
|
|
168
|
+
var(--token-side-nav-wrapper-padding-vertical)
|
|
169
|
+
var(--token-side-nav-wrapper-padding-horizontal);
|
|
170
|
+
overflow-y: auto;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.hds-side-nav__wrapper-footer {
|
|
174
|
+
padding:
|
|
175
|
+
var(--token-side-nav-wrapper-padding-vertical)
|
|
176
|
+
var(--token-side-nav-wrapper-padding-horizontal);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
// "HIDE-WHEN-MINIMIZED" SPECIAL CLASS
|
|
181
|
+
// this is a special class that is used to control which elements of the sidenav need to be:
|
|
182
|
+
// - hidden (immediately) when the sidenav is "minimized"
|
|
183
|
+
// - shown (transitioning their opacity) when the sidenav is "expanded"
|
|
184
|
+
|
|
185
|
+
.hds-side-nav-hide-when-minimized {
|
|
186
|
+
.hds-side-nav--is-mobile.hds-side-nav--is-minimized & {
|
|
187
|
+
visibility: hidden !important; // we need `!important` here to override the inline style applied to the single panels
|
|
188
|
+
opacity: 0;
|
|
189
|
+
transition: none;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.hds-side-nav--is-mobile.hds-side-nav--is-not-minimized &,
|
|
193
|
+
.hds-side-nav--is-desktop & {
|
|
194
|
+
visibility: visible;
|
|
195
|
+
opacity: 1;
|
|
196
|
+
transition:
|
|
197
|
+
opacity var(--hds-app-sidenav-animation-duration)
|
|
198
|
+
var(--hds-app-sidenav-animation-easing)
|
|
199
|
+
var(--hds-app-sidenav-animation-delay);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) HashiCorp, Inc.
|
|
3
|
+
* SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
//
|
|
7
|
+
// SIDE-NAV - VARS
|
|
8
|
+
//
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
// LOCAL VARIABLES
|
|
12
|
+
// we use `hds-app` as prefix to distinguish them from the normal tokens
|
|
13
|
+
// notice: they may be overwritten at consumer-level side if needed by re-defining the variables in a container element
|
|
14
|
+
|
|
15
|
+
:root {
|
|
16
|
+
// breakpoint
|
|
17
|
+
--hds-app-desktop-breakpoint: 1088px; // this is used only to read its value via JS and set the `hds-side-nav--is-desktop` class
|
|
18
|
+
// widths
|
|
19
|
+
--hds-app-sidenav-width-minimized: 80px;
|
|
20
|
+
--hds-app-sidenav-width-expanded: 280px;
|
|
21
|
+
--hds-app-sidenav-width-fixed: var(--hds-app-sidenav-width-expanded);
|
|
22
|
+
// sidebar menu
|
|
23
|
+
--hds-app-sidenav-menu-button-y-shift: 84px;
|
|
24
|
+
// animation
|
|
25
|
+
--hds-app-sidenav-animation-duration: 250ms;
|
|
26
|
+
--hds-app-sidenav-animation-delay: var(--hds-app-sidenav-animation-duration);
|
|
27
|
+
--hds-app-sidenav-animation-easing: cubic-bezier(0.65, 0, 0.35, 1);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// reduced motion
|
|
31
|
+
|
|
32
|
+
@media (prefers-reduced-motion) {
|
|
33
|
+
:root {
|
|
34
|
+
--hds-app-sidenav-animation-duration: 0;
|
|
35
|
+
}
|
|
36
|
+
}
|