@abstraks-dev/ui-library 1.2.0 → 1.2.2
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/README.md +6 -0
- package/dist/__tests__/Footer.test.js +57 -22
- package/dist/components/Footer.js +24 -36
- package/dist/components/Header.js +1 -1
- package/dist/components/SideMenu.js +28 -0
- package/dist/index.js +8 -0
- package/dist/styles/footer.css +109 -17
- package/dist/styles/footer.css.map +1 -1
- package/dist/styles/footer.scss +114 -23
- package/dist/styles/header.css +4 -3
- package/dist/styles/header.css.map +1 -1
- package/dist/styles/header.scss +15 -16
- package/dist/styles/main.css +140 -21
- package/dist/styles/main.css.map +1 -1
- package/dist/styles/search.css +5 -1
- package/dist/styles/search.css.map +1 -1
- package/dist/styles/search.scss +4 -1
- package/dist/styles/side-menu.css +22 -0
- package/dist/styles/side-menu.css.map +1 -1
- package/dist/styles/side-menu.scss +27 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -57,6 +57,12 @@ npm run build-css:watch
|
|
|
57
57
|
npm run build-css:compressed
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
+
## Production Storybook
|
|
61
|
+
|
|
62
|
+
You can view the latest production build of the UI Library Storybook here:
|
|
63
|
+
|
|
64
|
+
[UI-Library Site](https://main.ddpmt4w9k9d7q.amplifyapp.com/?path=/docs/abstraks-ui-library--docs)
|
|
65
|
+
|
|
60
66
|
## Deployment
|
|
61
67
|
|
|
62
68
|
This library supports both manual and automated deployment to npm using GitHub Actions.
|
|
@@ -16,39 +16,32 @@ afterAll(() => {
|
|
|
16
16
|
describe('Footer', () => {
|
|
17
17
|
it('renders with default props', () => {
|
|
18
18
|
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Footer.default, {
|
|
19
|
-
|
|
19
|
+
navigationOne: /*#__PURE__*/_react.default.createElement("li", null, "NavItem")
|
|
20
20
|
}));
|
|
21
21
|
expect(_react2.screen.getByRole('contentinfo')).toBeInTheDocument();
|
|
22
22
|
expect(_react2.screen.getByText('NavItem')).toBeInTheDocument();
|
|
23
23
|
});
|
|
24
|
-
it('renders
|
|
25
|
-
// Mock useWindowSize to return mobile width
|
|
26
|
-
jest.spyOn(require('../utils/useWindowSize'), 'useWindowSize').mockReturnValue({
|
|
27
|
-
width: 500
|
|
28
|
-
});
|
|
24
|
+
it('renders navigation sections', () => {
|
|
29
25
|
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Footer.default, {
|
|
30
|
-
|
|
26
|
+
navigationOne: /*#__PURE__*/_react.default.createElement("li", null, "Section1"),
|
|
27
|
+
navigationTwo: /*#__PURE__*/_react.default.createElement("li", null, "Section2"),
|
|
28
|
+
navigationThree: /*#__PURE__*/_react.default.createElement("li", null, "Section3")
|
|
31
29
|
}));
|
|
32
|
-
expect(_react2.screen.
|
|
33
|
-
expect(_react2.screen.getByText('
|
|
30
|
+
expect(_react2.screen.getByText('Section1')).toBeInTheDocument();
|
|
31
|
+
expect(_react2.screen.getByText('Section2')).toBeInTheDocument();
|
|
32
|
+
expect(_react2.screen.getByText('Section3')).toBeInTheDocument();
|
|
34
33
|
});
|
|
35
|
-
it('renders
|
|
36
|
-
jest.spyOn(require('../utils/useWindowSize'), 'useWindowSize').mockReturnValue({
|
|
37
|
-
width: 1024
|
|
38
|
-
});
|
|
34
|
+
it('renders copyright when not authenticated', () => {
|
|
39
35
|
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Footer.default, {
|
|
40
|
-
|
|
36
|
+
hasAuth: false
|
|
41
37
|
}));
|
|
42
|
-
expect(_react2.screen.
|
|
43
|
-
expect(_react2.screen.getByText('DesktopNav')).toBeInTheDocument();
|
|
38
|
+
expect(_react2.screen.getByText(/© 2025 Abstraks. All rights reserved./)).toBeInTheDocument();
|
|
44
39
|
});
|
|
45
|
-
it('renders auth menu when hasAuth is true
|
|
46
|
-
|
|
47
|
-
width: 500
|
|
48
|
-
});
|
|
40
|
+
it('renders auth menu when hasAuth is true', () => {
|
|
41
|
+
const authMenuContent = /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("li", null, /*#__PURE__*/_react.default.createElement("span", null, "Home")), /*#__PURE__*/_react.default.createElement("li", null, /*#__PURE__*/_react.default.createElement("span", null, "Search")), /*#__PURE__*/_react.default.createElement("li", null, /*#__PURE__*/_react.default.createElement("span", null, "Add")), /*#__PURE__*/_react.default.createElement("li", null, /*#__PURE__*/_react.default.createElement("span", null, "Profile")));
|
|
49
42
|
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Footer.default, {
|
|
50
43
|
hasAuth: true,
|
|
51
|
-
|
|
44
|
+
authMenu: authMenuContent
|
|
52
45
|
}));
|
|
53
46
|
expect(_react2.screen.getByLabelText('User navigation')).toBeInTheDocument();
|
|
54
47
|
expect(_react2.screen.getByText('Home')).toBeInTheDocument();
|
|
@@ -56,11 +49,53 @@ describe('Footer', () => {
|
|
|
56
49
|
expect(_react2.screen.getByText('Add')).toBeInTheDocument();
|
|
57
50
|
expect(_react2.screen.getByText('Profile')).toBeInTheDocument();
|
|
58
51
|
});
|
|
52
|
+
it('applies box shadow based on auth state and screen size', () => {
|
|
53
|
+
// Test desktop without auth (should have box shadow)
|
|
54
|
+
jest.spyOn(require('../utils/useWindowSize'), 'useWindowSize').mockReturnValue({
|
|
55
|
+
width: 1024
|
|
56
|
+
});
|
|
57
|
+
const {
|
|
58
|
+
rerender
|
|
59
|
+
} = (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Footer.default, {
|
|
60
|
+
hasAuth: false
|
|
61
|
+
}));
|
|
62
|
+
expect(_react2.screen.getByRole('contentinfo')).toHaveStyle('box-shadow: 0 -2px 4px rgba(0, 0, 0, 0.1)');
|
|
63
|
+
|
|
64
|
+
// Test mobile with auth (should have box shadow)
|
|
65
|
+
jest.spyOn(require('../utils/useWindowSize'), 'useWindowSize').mockReturnValue({
|
|
66
|
+
width: 500
|
|
67
|
+
});
|
|
68
|
+
rerender(/*#__PURE__*/_react.default.createElement(_Footer.default, {
|
|
69
|
+
hasAuth: true
|
|
70
|
+
}));
|
|
71
|
+
expect(_react2.screen.getByRole('contentinfo')).toHaveStyle('box-shadow: 0 -2px 4px rgba(0, 0, 0, 0.1)');
|
|
72
|
+
});
|
|
59
73
|
it('applies custom aria-label', () => {
|
|
60
74
|
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Footer.default, {
|
|
61
|
-
|
|
75
|
+
navigationOne: /*#__PURE__*/_react.default.createElement("li", null, "Nav"),
|
|
62
76
|
"aria-label": "Custom Footer"
|
|
63
77
|
}));
|
|
64
78
|
expect(_react2.screen.getByRole('contentinfo')).toHaveAttribute('aria-label', 'Custom Footer');
|
|
65
79
|
});
|
|
80
|
+
it('renders with custom id', () => {
|
|
81
|
+
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Footer.default, {
|
|
82
|
+
id: "custom-footer",
|
|
83
|
+
navigationOne: /*#__PURE__*/_react.default.createElement("li", null, "Nav")
|
|
84
|
+
}));
|
|
85
|
+
expect(_react2.screen.getByRole('contentinfo')).toHaveAttribute('id', 'custom-footer');
|
|
86
|
+
});
|
|
87
|
+
it('renders without copyright when hasAuth is true', () => {
|
|
88
|
+
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Footer.default, {
|
|
89
|
+
hasAuth: true,
|
|
90
|
+
authMenu: /*#__PURE__*/_react.default.createElement("li", null, "Menu")
|
|
91
|
+
}));
|
|
92
|
+
expect(_react2.screen.queryByText(/© 2025 Abstraks. All rights reserved./)).not.toBeInTheDocument();
|
|
93
|
+
});
|
|
94
|
+
it('renders with custom className', () => {
|
|
95
|
+
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_Footer.default, {
|
|
96
|
+
className: "custom-footer",
|
|
97
|
+
navigationOne: /*#__PURE__*/_react.default.createElement("li", null, "Nav")
|
|
98
|
+
}));
|
|
99
|
+
expect(_react2.screen.getByRole('contentinfo')).toHaveClass('footer custom-footer');
|
|
100
|
+
});
|
|
66
101
|
});
|
|
@@ -8,7 +8,6 @@ var _react = _interopRequireWildcard(require("react"));
|
|
|
8
8
|
var _propTypes = require("prop-types");
|
|
9
9
|
var _useWindowSize = require("../utils/useWindowSize");
|
|
10
10
|
var _ssrSafeId = require("../utils/ssrSafeId");
|
|
11
|
-
var _Animation = require("./Animation");
|
|
12
11
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
13
12
|
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
14
13
|
/**
|
|
@@ -20,12 +19,15 @@ function _extends() { return _extends = Object.assign ? Object.assign.bind() : f
|
|
|
20
19
|
const Footer = exports.Footer = /*#__PURE__*/(0, _react.forwardRef)(({
|
|
21
20
|
id,
|
|
22
21
|
className = '',
|
|
23
|
-
|
|
22
|
+
navigationOne = null,
|
|
23
|
+
navigationTwo = null,
|
|
24
|
+
navigationThree = null,
|
|
24
25
|
signInLink = null,
|
|
25
26
|
signUpLink = null,
|
|
26
27
|
avatarSrc = null,
|
|
27
28
|
ellipsesList = [],
|
|
28
29
|
hasAuth = false,
|
|
30
|
+
authMenu = null,
|
|
29
31
|
'aria-label': ariaLabel = 'Footer',
|
|
30
32
|
componentName = 'footer',
|
|
31
33
|
additionalClassName = '',
|
|
@@ -35,54 +37,40 @@ const Footer = exports.Footer = /*#__PURE__*/(0, _react.forwardRef)(({
|
|
|
35
37
|
const generateId = (0, _ssrSafeId.useStableId)('footer');
|
|
36
38
|
const finalId = id || generateId();
|
|
37
39
|
const finalClassName = className || additionalClassName;
|
|
40
|
+
const shouldApplyBoxShadow = !hasAuth && size.width > 768 || hasAuth && size.width < 768;
|
|
38
41
|
return /*#__PURE__*/_react.default.createElement("footer", _extends({
|
|
39
42
|
ref: ref,
|
|
40
43
|
id: finalId,
|
|
41
44
|
className: `${componentName} ${finalClassName}`,
|
|
42
45
|
"data-testid": componentName,
|
|
43
46
|
role: "contentinfo",
|
|
44
|
-
"aria-label": ariaLabel
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
},
|
|
49
|
-
/*#__PURE__*/
|
|
50
|
-
// mobile
|
|
51
|
-
_react.default.createElement("div", {
|
|
47
|
+
"aria-label": ariaLabel,
|
|
48
|
+
style: shouldApplyBoxShadow ? {
|
|
49
|
+
boxShadow: '0 -2px 4px rgba(0, 0, 0, 0.1)'
|
|
50
|
+
} : undefined
|
|
51
|
+
}, restProps), /*#__PURE__*/_react.default.createElement("div", {
|
|
52
52
|
className: "navigation",
|
|
53
53
|
role: "navigation",
|
|
54
|
-
"aria-label": "
|
|
55
|
-
}, !hasAuth ? /*#__PURE__*/_react.default.createElement("ul", {
|
|
54
|
+
"aria-label": "footer navigation"
|
|
55
|
+
}, !hasAuth ? /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("ul", {
|
|
56
56
|
className: "unordered-list",
|
|
57
57
|
role: "list"
|
|
58
|
-
}, navigation) : /*#__PURE__*/_react.default.createElement("ul", {
|
|
59
|
-
className: "unordered-list auth-menu",
|
|
60
|
-
role: "list",
|
|
61
|
-
"aria-label": "User navigation"
|
|
62
58
|
}, /*#__PURE__*/_react.default.createElement("li", {
|
|
63
|
-
className: "list-item",
|
|
59
|
+
className: "list-item list-one",
|
|
64
60
|
role: "listitem"
|
|
65
|
-
},
|
|
66
|
-
className: "list-item",
|
|
61
|
+
}, navigationOne), /*#__PURE__*/_react.default.createElement("li", {
|
|
62
|
+
className: "list-item list-two",
|
|
67
63
|
role: "listitem"
|
|
68
|
-
},
|
|
69
|
-
className: "list-item",
|
|
64
|
+
}, navigationTwo), /*#__PURE__*/_react.default.createElement("li", {
|
|
65
|
+
className: "list-item list-three",
|
|
70
66
|
role: "listitem"
|
|
71
|
-
},
|
|
72
|
-
className: "
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
className: "navigation",
|
|
79
|
-
"data-testid": "navigation",
|
|
80
|
-
role: "navigation",
|
|
81
|
-
"aria-label": "Desktop footer navigation"
|
|
82
|
-
}, /*#__PURE__*/_react.default.createElement("ul", {
|
|
83
|
-
className: "unordered-list",
|
|
84
|
-
role: "list"
|
|
85
|
-
}, navigation))));
|
|
67
|
+
}, navigationThree)), /*#__PURE__*/_react.default.createElement("div", {
|
|
68
|
+
className: "bottom"
|
|
69
|
+
}, "\xA9 ", new Date().getFullYear(), " Abstraks. All rights reserved.")) : /*#__PURE__*/_react.default.createElement("ul", {
|
|
70
|
+
className: "unordered-list auth-menu",
|
|
71
|
+
role: "list",
|
|
72
|
+
"aria-label": "User navigation"
|
|
73
|
+
}, authMenu)));
|
|
86
74
|
});
|
|
87
75
|
Footer.displayName = 'Footer';
|
|
88
76
|
Footer.propTypes = {
|
|
@@ -208,7 +208,7 @@ const Header = exports.Header = /*#__PURE__*/(0, _react.forwardRef)(({
|
|
|
208
208
|
onKeyDown: handleKeyDown
|
|
209
209
|
}, restProps), /*#__PURE__*/_react.default.createElement("div", {
|
|
210
210
|
className: isMobile ? 'container-mobile' : 'container-large'
|
|
211
|
-
}, logo, hasAuth && search, isMobile ? /*#__PURE__*/_react.default.createElement(_SideMenu.SideMenu, {
|
|
211
|
+
}, logo, hasAuth && !isMobile && search, isMobile ? /*#__PURE__*/_react.default.createElement(_SideMenu.SideMenu, {
|
|
212
212
|
direction: "vertical",
|
|
213
213
|
position: "top",
|
|
214
214
|
isOpen: isMenuOpen,
|
|
@@ -84,6 +84,34 @@ const SideMenu = exports.SideMenu = /*#__PURE__*/(0, _react.forwardRef)(({
|
|
|
84
84
|
const generateId = (0, _ssrSafeId.useStableId)('side-menu');
|
|
85
85
|
const finalId = id || testId || generateId();
|
|
86
86
|
const finalClassName = className || additionalClassName;
|
|
87
|
+
|
|
88
|
+
// Handle body scroll locking when menu is open
|
|
89
|
+
(0, _react.useEffect)(() => {
|
|
90
|
+
if (typeof document !== 'undefined') {
|
|
91
|
+
if (isOpen) {
|
|
92
|
+
// Store current scroll position
|
|
93
|
+
const scrollY = window.scrollY;
|
|
94
|
+
document.body.style.top = `-${scrollY}px`;
|
|
95
|
+
document.body.classList.add('side-menu-open');
|
|
96
|
+
} else {
|
|
97
|
+
document.body.classList.remove('side-menu-open');
|
|
98
|
+
// Restore scroll position
|
|
99
|
+
const scrollY = document.body.style.top;
|
|
100
|
+
document.body.style.top = '';
|
|
101
|
+
if (scrollY) {
|
|
102
|
+
window.scrollTo(0, parseInt(scrollY || '0', 10));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Cleanup function
|
|
108
|
+
return () => {
|
|
109
|
+
if (typeof document !== 'undefined') {
|
|
110
|
+
document.body.classList.remove('side-menu-open');
|
|
111
|
+
document.body.style.top = '';
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}, [isOpen]);
|
|
87
115
|
const handleToggle = (0, _react.useCallback)(() => {
|
|
88
116
|
if (isOpen) {
|
|
89
117
|
onClose();
|
package/dist/index.js
CHANGED
|
@@ -17,6 +17,7 @@ var _exportNames = {
|
|
|
17
17
|
DragAndDrop: true,
|
|
18
18
|
Error: true,
|
|
19
19
|
FileInput: true,
|
|
20
|
+
Footer: true,
|
|
20
21
|
Form: true,
|
|
21
22
|
Header: true,
|
|
22
23
|
Heading: true,
|
|
@@ -228,6 +229,12 @@ Object.defineProperty(exports, "Filter", {
|
|
|
228
229
|
return _Filter.Filter;
|
|
229
230
|
}
|
|
230
231
|
});
|
|
232
|
+
Object.defineProperty(exports, "Footer", {
|
|
233
|
+
enumerable: true,
|
|
234
|
+
get: function () {
|
|
235
|
+
return _Footer.Footer;
|
|
236
|
+
}
|
|
237
|
+
});
|
|
231
238
|
Object.defineProperty(exports, "Form", {
|
|
232
239
|
enumerable: true,
|
|
233
240
|
get: function () {
|
|
@@ -427,6 +434,7 @@ var _Crud = _interopRequireDefault(require("./components/Crud"));
|
|
|
427
434
|
var _DragAndDrop = _interopRequireDefault(require("./components/DragAndDrop"));
|
|
428
435
|
var _Error = _interopRequireDefault(require("./components/Error"));
|
|
429
436
|
var _FileInput = _interopRequireDefault(require("./components/FileInput"));
|
|
437
|
+
var _Footer = require("./components/Footer");
|
|
430
438
|
var _Form = _interopRequireDefault(require("./components/Form"));
|
|
431
439
|
var _Header = _interopRequireDefault(require("./components/Header"));
|
|
432
440
|
var _Heading = _interopRequireDefault(require("./components/Heading"));
|
package/dist/styles/footer.css
CHANGED
|
@@ -115,51 +115,143 @@
|
|
|
115
115
|
align-items: center;
|
|
116
116
|
flex-direction: row;
|
|
117
117
|
padding: 15px;
|
|
118
|
+
/* Absolute positioning - reliably pins footer to bottom */
|
|
119
|
+
position: absolute;
|
|
120
|
+
bottom: 0;
|
|
121
|
+
left: 0;
|
|
122
|
+
right: 0;
|
|
123
|
+
background: #fff;
|
|
124
|
+
box-shadow: 0 -2px 4px rgba(0, 0, 0, 0.1);
|
|
125
|
+
/* Ensure footer stays above other content */
|
|
126
|
+
z-index: 200;
|
|
118
127
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
justify-content: flex-end;
|
|
123
|
-
}
|
|
128
|
+
.footer .navigation {
|
|
129
|
+
display: flex;
|
|
130
|
+
flex-direction: column;
|
|
124
131
|
}
|
|
125
132
|
.footer .navigation .unordered-list {
|
|
126
133
|
display: flex;
|
|
127
134
|
flex-direction: column;
|
|
135
|
+
width: 100%;
|
|
128
136
|
}
|
|
129
137
|
@media (min-width: 768px) {
|
|
130
138
|
.footer .navigation .unordered-list {
|
|
131
|
-
display:
|
|
139
|
+
display: flex;
|
|
132
140
|
flex-direction: row;
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
padding: 0;
|
|
136
|
-
margin: 0;
|
|
141
|
+
justify-content: space-between;
|
|
142
|
+
width: 50%;
|
|
137
143
|
}
|
|
138
144
|
}
|
|
139
145
|
.footer .navigation .unordered-list.auth-menu {
|
|
140
|
-
border-top: 1px solid #e9ecef;
|
|
141
146
|
flex-direction: row;
|
|
142
147
|
justify-content: space-between;
|
|
148
|
+
display: flex;
|
|
149
|
+
}
|
|
150
|
+
@media (min-width: 768px) {
|
|
151
|
+
.footer .navigation .unordered-list.auth-menu {
|
|
152
|
+
display: none;
|
|
153
|
+
}
|
|
143
154
|
}
|
|
144
155
|
.footer .navigation .unordered-list.auth-menu .list-item {
|
|
145
156
|
display: inline-flex;
|
|
146
|
-
|
|
157
|
+
align-items: center;
|
|
158
|
+
}
|
|
159
|
+
@media (min-width: 768px) {
|
|
160
|
+
.footer .navigation .unordered-list.auth-menu .list-item {
|
|
161
|
+
width: 33.3%;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
.footer .navigation .bottom {
|
|
165
|
+
display: flex;
|
|
166
|
+
flex-direction: row;
|
|
167
|
+
margin-top: 10px;
|
|
168
|
+
font-size: 0.875rem;
|
|
169
|
+
color: #6c757d;
|
|
147
170
|
}
|
|
148
|
-
.footer .navigation .
|
|
171
|
+
.footer .navigation .list-item {
|
|
149
172
|
display: flex;
|
|
150
173
|
}
|
|
151
174
|
@media (min-width: 768px) {
|
|
152
|
-
.footer .navigation .
|
|
175
|
+
.footer .navigation .list-item {
|
|
153
176
|
display: inline-flex;
|
|
154
|
-
padding: 0
|
|
177
|
+
padding: 10px 0;
|
|
155
178
|
}
|
|
156
179
|
}
|
|
157
|
-
.footer .
|
|
180
|
+
.footer .anchor {
|
|
158
181
|
color: #6c757d;
|
|
159
182
|
text-decoration: none;
|
|
160
183
|
}
|
|
161
|
-
.footer .
|
|
184
|
+
.footer .anchor:hover {
|
|
162
185
|
color: #333;
|
|
163
186
|
}
|
|
164
187
|
|
|
188
|
+
/* Global styles to support absolute positioned footer */
|
|
189
|
+
/*
|
|
190
|
+
* Usage: Apply these classes to your layout:
|
|
191
|
+
* - Add 'sticky-footer-layout' class to your main container
|
|
192
|
+
* - Add 'main-content' class to your content wrapper
|
|
193
|
+
* - The footer will be absolutely positioned at the bottom
|
|
194
|
+
*/
|
|
195
|
+
html.sticky-footer-layout,
|
|
196
|
+
body.sticky-footer-layout {
|
|
197
|
+
height: 100%;
|
|
198
|
+
margin: 0;
|
|
199
|
+
padding: 0;
|
|
200
|
+
/* Force proper height on mobile */
|
|
201
|
+
}
|
|
202
|
+
@media (max-width: 767px) {
|
|
203
|
+
html.sticky-footer-layout,
|
|
204
|
+
body.sticky-footer-layout {
|
|
205
|
+
height: 100%;
|
|
206
|
+
min-height: 100vh;
|
|
207
|
+
margin: 0;
|
|
208
|
+
padding: 0;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.sticky-footer-layout {
|
|
213
|
+
position: relative;
|
|
214
|
+
min-height: 100vh;
|
|
215
|
+
margin: 0;
|
|
216
|
+
padding: 0;
|
|
217
|
+
/* Add bottom padding to prevent content hiding behind footer */
|
|
218
|
+
padding-bottom: 80px; /* Adjust based on footer height */
|
|
219
|
+
/* Ensure layout works on all screen sizes */
|
|
220
|
+
/* Footer positioning within the layout */
|
|
221
|
+
}
|
|
222
|
+
@media (max-width: 767px) {
|
|
223
|
+
.sticky-footer-layout {
|
|
224
|
+
position: relative;
|
|
225
|
+
min-height: 100vh;
|
|
226
|
+
padding-bottom: 100px; /* Slightly more padding on mobile */
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
.sticky-footer-layout .main-content {
|
|
230
|
+
width: 100%;
|
|
231
|
+
padding-bottom: 20px; /* Additional content padding */
|
|
232
|
+
/* Mobile-specific main content */
|
|
233
|
+
}
|
|
234
|
+
@media (max-width: 767px) {
|
|
235
|
+
.sticky-footer-layout .main-content {
|
|
236
|
+
width: 100%;
|
|
237
|
+
padding-bottom: 20px;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
.sticky-footer-layout .footer {
|
|
241
|
+
position: absolute;
|
|
242
|
+
bottom: 0;
|
|
243
|
+
left: 0;
|
|
244
|
+
right: 0;
|
|
245
|
+
/* Mobile-specific footer */
|
|
246
|
+
}
|
|
247
|
+
@media (max-width: 767px) {
|
|
248
|
+
.sticky-footer-layout .footer {
|
|
249
|
+
position: absolute;
|
|
250
|
+
bottom: 0;
|
|
251
|
+
left: 0;
|
|
252
|
+
right: 0;
|
|
253
|
+
width: 100%;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
165
257
|
/*# sourceMappingURL=footer.css.map */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sourceRoot":"","sources":["../../src/styles/_variables.scss","../../src/styles/footer.scss"],"names":[],"mappings":"AAgSA;EAJE;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;;;AC1RF;EACC;EACA;EACA;EACA
|
|
1
|
+
{"version":3,"sourceRoot":"","sources":["../../src/styles/_variables.scss","../../src/styles/footer.scss"],"names":[],"mappings":"AAgSA;EAJE;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;;;AC1RF;EACC;EACA;EACA;EACA;AAEA;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA,SDyDgB;;ACvDhB;EACC;EACA;;AAEA;EACC;EACA;EACA;;AAEA;EALD;IAME;IACA;IACA;IACA;;;AAGD;EACC;EACA;EACA;;AAEA;EALD;IAME;;;AAGD;EACC;EACA;;AAEA;EAJD;IAKE;;;AAMJ;EACC;EACA;EACA;EACA;EACA,OD6BQ;;AC1BT;EACC;;AAEA;EAHD;IAIE;IACA;;;AAKH;EACC,ODeS;ECdT;;AAEA;EACC,ODnDe;;;ACwDlB;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMA;AAAA;EAEC;EACA;EACA;AAEA;;AACA;EAPD;AAAA;IAQE;IACA;IACA;IACA;;;;AAIF;EACC;EACA;EACA;EACA;AAEA;EACA;AAEA;AAkBA;;AAjBA;EAVD;IAWE;IACA;IACA;;;AAGD;EACC;EACA;AAEA;;AACA;EALD;IAME;IACA;;;AAKF;EACC;EACA;EACA;EACA;AAEA;;AACA;EAPD;IAQE;IACA;IACA;IACA;IACA","file":"footer.css"}
|
package/dist/styles/footer.scss
CHANGED
|
@@ -6,53 +6,144 @@
|
|
|
6
6
|
flex-direction: row;
|
|
7
7
|
padding: 15px;
|
|
8
8
|
|
|
9
|
+
/* Absolute positioning - reliably pins footer to bottom */
|
|
10
|
+
position: absolute;
|
|
11
|
+
bottom: 0;
|
|
12
|
+
left: 0;
|
|
13
|
+
right: 0;
|
|
14
|
+
background: #fff;
|
|
15
|
+
box-shadow: 0 -2px 4px rgba(0, 0, 0, 0.1);
|
|
16
|
+
|
|
17
|
+
/* Ensure footer stays above other content */
|
|
18
|
+
z-index: $z-index-sticky;
|
|
19
|
+
|
|
9
20
|
.navigation {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
justify-content: flex-end;
|
|
13
|
-
}
|
|
21
|
+
display: flex;
|
|
22
|
+
flex-direction: column;
|
|
14
23
|
|
|
15
24
|
.unordered-list {
|
|
16
25
|
display: flex;
|
|
17
26
|
flex-direction: column;
|
|
27
|
+
width: 100%;
|
|
18
28
|
|
|
19
29
|
@media (min-width: 768px) {
|
|
20
|
-
display:
|
|
30
|
+
display: flex;
|
|
21
31
|
flex-direction: row;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
padding: 0;
|
|
25
|
-
margin: 0;
|
|
32
|
+
justify-content: space-between;
|
|
33
|
+
width: 50%;
|
|
26
34
|
}
|
|
27
35
|
|
|
28
36
|
&.auth-menu {
|
|
29
|
-
border-top: 1px solid $gray-200;
|
|
30
37
|
flex-direction: row;
|
|
31
38
|
justify-content: space-between;
|
|
32
|
-
|
|
33
|
-
.list-item {
|
|
34
|
-
display: inline-flex;
|
|
35
|
-
/* width: 25%; */
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
.list-item {
|
|
40
39
|
display: flex;
|
|
41
40
|
|
|
42
41
|
@media (min-width: 768px) {
|
|
42
|
+
display: none;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.list-item {
|
|
43
46
|
display: inline-flex;
|
|
44
|
-
|
|
47
|
+
align-items: center;
|
|
48
|
+
|
|
49
|
+
@media (min-width: 768px) {
|
|
50
|
+
width: 33.3%;
|
|
51
|
+
}
|
|
45
52
|
}
|
|
46
53
|
}
|
|
47
54
|
}
|
|
48
55
|
|
|
49
|
-
.
|
|
56
|
+
.bottom {
|
|
57
|
+
display: flex;
|
|
58
|
+
flex-direction: row;
|
|
59
|
+
margin-top: 10px;
|
|
60
|
+
font-size: 0.875rem;
|
|
50
61
|
color: $gray-600;
|
|
51
|
-
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.list-item {
|
|
65
|
+
display: flex;
|
|
52
66
|
|
|
53
|
-
|
|
54
|
-
|
|
67
|
+
@media (min-width: 768px) {
|
|
68
|
+
display: inline-flex;
|
|
69
|
+
padding: 10px 0;
|
|
55
70
|
}
|
|
56
71
|
}
|
|
57
72
|
}
|
|
73
|
+
|
|
74
|
+
.anchor {
|
|
75
|
+
color: $gray-600;
|
|
76
|
+
text-decoration: none;
|
|
77
|
+
|
|
78
|
+
&:hover {
|
|
79
|
+
color: $color-font-body;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/* Global styles to support absolute positioned footer */
|
|
85
|
+
/*
|
|
86
|
+
* Usage: Apply these classes to your layout:
|
|
87
|
+
* - Add 'sticky-footer-layout' class to your main container
|
|
88
|
+
* - Add 'main-content' class to your content wrapper
|
|
89
|
+
* - The footer will be absolutely positioned at the bottom
|
|
90
|
+
*/
|
|
91
|
+
html.sticky-footer-layout,
|
|
92
|
+
body.sticky-footer-layout {
|
|
93
|
+
height: 100%;
|
|
94
|
+
margin: 0;
|
|
95
|
+
padding: 0;
|
|
96
|
+
|
|
97
|
+
/* Force proper height on mobile */
|
|
98
|
+
@media (max-width: 767px) {
|
|
99
|
+
height: 100%;
|
|
100
|
+
min-height: 100vh;
|
|
101
|
+
margin: 0;
|
|
102
|
+
padding: 0;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.sticky-footer-layout {
|
|
107
|
+
position: relative;
|
|
108
|
+
min-height: 100vh;
|
|
109
|
+
margin: 0;
|
|
110
|
+
padding: 0;
|
|
111
|
+
|
|
112
|
+
/* Add bottom padding to prevent content hiding behind footer */
|
|
113
|
+
padding-bottom: 80px; /* Adjust based on footer height */
|
|
114
|
+
|
|
115
|
+
/* Ensure layout works on all screen sizes */
|
|
116
|
+
@media (max-width: 767px) {
|
|
117
|
+
position: relative;
|
|
118
|
+
min-height: 100vh;
|
|
119
|
+
padding-bottom: 100px; /* Slightly more padding on mobile */
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.main-content {
|
|
123
|
+
width: 100%;
|
|
124
|
+
padding-bottom: 20px; /* Additional content padding */
|
|
125
|
+
|
|
126
|
+
/* Mobile-specific main content */
|
|
127
|
+
@media (max-width: 767px) {
|
|
128
|
+
width: 100%;
|
|
129
|
+
padding-bottom: 20px;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/* Footer positioning within the layout */
|
|
134
|
+
.footer {
|
|
135
|
+
position: absolute;
|
|
136
|
+
bottom: 0;
|
|
137
|
+
left: 0;
|
|
138
|
+
right: 0;
|
|
139
|
+
|
|
140
|
+
/* Mobile-specific footer */
|
|
141
|
+
@media (max-width: 767px) {
|
|
142
|
+
position: absolute;
|
|
143
|
+
bottom: 0;
|
|
144
|
+
left: 0;
|
|
145
|
+
right: 0;
|
|
146
|
+
width: 100%;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
58
149
|
}
|
package/dist/styles/header.css
CHANGED
|
@@ -139,8 +139,10 @@
|
|
|
139
139
|
flex-direction: row;
|
|
140
140
|
align-items: center;
|
|
141
141
|
}
|
|
142
|
-
|
|
143
|
-
|
|
142
|
+
@media (min-width: 768px) {
|
|
143
|
+
.header .container-large {
|
|
144
|
+
justify-content: space-between;
|
|
145
|
+
}
|
|
144
146
|
}
|
|
145
147
|
.header .container-mobile {
|
|
146
148
|
width: 100%;
|
|
@@ -287,7 +289,6 @@
|
|
|
287
289
|
@media (min-width: 768px) {
|
|
288
290
|
.header .navigation .unordered-list .list-item {
|
|
289
291
|
display: inline-flex;
|
|
290
|
-
padding: 0 15px;
|
|
291
292
|
}
|
|
292
293
|
}
|
|
293
294
|
.header .navigation .unordered-list .list-item [role=menuitem] {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sourceRoot":"","sources":["../../src/styles/_variables.scss","../../src/styles/header.scss"],"names":[],"mappings":"AAgSA;EAJE;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;;;AC1RF;
|
|
1
|
+
{"version":3,"sourceRoot":"","sources":["../../src/styles/_variables.scss","../../src/styles/header.scss"],"names":[],"mappings":"AAgSA;EAJE;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;;;AC1RF;EACC;EACA;EACA,SDqEgB;ECpEhB;EACA;EACA;EACA;EACA;EACA,kBDca;ECbb;EACA;;AAGA;EACC;EACA;;AAID;EApBD;IAqBE;IACA;;;AAGD;EACC;EACA;EACA;EACA;;AAEA;EAND;IAOE;;;AAIF;EACC;EACA;EACA;;AAEA;EACC;EACA;EACA;;AAEA;EACC,kBDxBU;;AC4BV;EACC;EACA;EACA;EACA,kBDhCS;;ACkCT;EACC;;AAIF;EACC,kBDxCS;;AC+Cb;AAAA;EAEC;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;EACC;;AAGD;AAAA;EACC;EACA;;AAKD;EADD;IAEE;IACA;;;AAGD;EACC;EACA;;AAEA;EAJD;IAKE;IACA;IACA;IACA;IACA;IACA;;;AAGD;EACC;;AAEA;EAHD;IAIE;IACA;;;AAIA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACC;;AAGD;EACC;EACA;;AAGD;EACC;;AAGD;EACC;EACA,SDtEY;ECuEZ;EACA;EACA;EACA;EACA;EACA;EACA;EAGA,kBDhIO;ECiIP;EACA;EACA;EACA;EACA;;AAIA;EArBD;IAsBE;IACA;;;AAGD;EACC;EACA;EACA;;AAEA;EACC;EACA;;AAEA;EACC;EACA;EACA;EACA,ODzJQ;EC0JR;EACA;;AAEA;EAEC;EACA,ODpLK;;ACuLN;EACC;EACA;;AAUR;EACC;;AAEA;EAHD;IAIE;;;AAID;EACC;EACA;EACA;EACA;;AAEA;EACC;EACA;;AAMJ;EACC,ODxIQ;ECyIR;EACA;;AAEA;EACC,OD3Mc;;AC8Mf;EACC,ODnOY;ECoOZ;EACA;;AAID;EACC;IAEC,ODzNS;IC0NT;;;AAOJ;EAzPD;IA0PE;;EAEA;IACC;IACA;;;AAIF;EAlQD;IAmQE;;EAEA;IACC;;;AAKF;EACC;AAAA;AAAA;IAGC;IACA;IACA;;;;AAKH;EACC;EACA","file":"header.css"}
|