unigrid.css 0.3.0 → 0.3.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 +101 -101
- package/dist/dropdown.js +36 -36
- package/dist/scrollspy.js +57 -57
- package/dist/tabs.js +30 -30
- package/dist/unigrid.css +4608 -4501
- package/dist/unigrid.js +173 -124
- package/dist/unigrid.min.css +1 -1
- package/dist/unigrid.min.js +1 -1
- package/package.json +70 -41
- package/src/js/dropdown.js +49 -49
- package/src/js/index.js +20 -19
- package/src/js/modal.js +81 -0
- package/src/js/scrollspy.js +87 -87
- package/src/js/tabs.js +58 -58
- package/src/scss/_accordion.scss +123 -123
- package/src/scss/_broadside.scss +125 -125
- package/src/scss/_buttons.scss +241 -241
- package/src/scss/_card.scss +168 -168
- package/src/scss/_components.scss +140 -140
- package/src/scss/_container.scss +53 -53
- package/src/scss/_dropdown.scss +178 -178
- package/src/scss/_footer.scss +147 -147
- package/src/scss/_formats.scss +64 -64
- package/src/scss/_forms.scss +192 -192
- package/src/scss/_grid.scss +114 -114
- package/src/scss/_header.scss +169 -169
- package/src/scss/_hero.scss +262 -262
- package/src/scss/_mixins.scss +120 -120
- package/src/scss/_modal.scss +158 -0
- package/src/scss/_modules.scss +238 -238
- package/src/scss/_navbar.scss +341 -341
- package/src/scss/_pagination.scss +160 -160
- package/src/scss/_prose.scss +393 -393
- package/src/scss/_reset.scss +82 -82
- package/src/scss/_scrollspy.scss +62 -62
- package/src/scss/_section.scss +91 -91
- package/src/scss/_sidebar.scss +147 -147
- package/src/scss/_table.scss +122 -122
- package/src/scss/_tabs.scss +178 -178
- package/src/scss/_typography.scss +105 -105
- package/src/scss/_utilities.scss +79 -79
- package/src/scss/_variables.scss +183 -183
- package/src/scss/unigrid.scss +50 -49
- package/dist/index.js +0 -5
package/src/js/index.js
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unigrid.js — All interactive components bundled.
|
|
3
|
-
*
|
|
4
|
-
* Includes: dropdown, tabs, scrollspy
|
|
5
|
-
*
|
|
6
|
-
* Usage:
|
|
7
|
-
* <script src="dist/unigrid.js"></script>
|
|
8
|
-
* or
|
|
9
|
-
* <script src="dist/unigrid.min.js"></script>
|
|
10
|
-
*
|
|
11
|
-
* Individual files also available:
|
|
12
|
-
* <script src="dist/dropdown.js"></script>
|
|
13
|
-
* <script src="dist/tabs.js"></script>
|
|
14
|
-
* <script src="dist/scrollspy.js"></script>
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import './dropdown.js';
|
|
18
|
-
import './tabs.js';
|
|
19
|
-
import './scrollspy.js';
|
|
1
|
+
/**
|
|
2
|
+
* Unigrid.js — All interactive components bundled.
|
|
3
|
+
*
|
|
4
|
+
* Includes: dropdown, tabs, scrollspy
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* <script src="dist/unigrid.js"></script>
|
|
8
|
+
* or
|
|
9
|
+
* <script src="dist/unigrid.min.js"></script>
|
|
10
|
+
*
|
|
11
|
+
* Individual files also available:
|
|
12
|
+
* <script src="dist/dropdown.js"></script>
|
|
13
|
+
* <script src="dist/tabs.js"></script>
|
|
14
|
+
* <script src="dist/scrollspy.js"></script>
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import './dropdown.js';
|
|
18
|
+
import './tabs.js';
|
|
19
|
+
import './scrollspy.js';
|
|
20
|
+
import './modal.js';
|
package/src/js/modal.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unigrid Modal
|
|
3
|
+
*
|
|
4
|
+
* Opens/closes modals via data attributes.
|
|
5
|
+
* Closes on backdrop click, close button, or Escape key.
|
|
6
|
+
* Locks body scroll when open.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* <button data-ug-modal-open="my-modal">Open</button>
|
|
10
|
+
*
|
|
11
|
+
* <div class="ug-modal" id="my-modal">
|
|
12
|
+
* <div class="ug-modal__backdrop" data-ug-modal-close></div>
|
|
13
|
+
* <div class="ug-modal__dialog">
|
|
14
|
+
* <div class="ug-modal__header">
|
|
15
|
+
* <h3 class="ug-modal__title">Title</h3>
|
|
16
|
+
* <button class="ug-modal__close" data-ug-modal-close>×</button>
|
|
17
|
+
* </div>
|
|
18
|
+
* <div class="ug-modal__body">Content</div>
|
|
19
|
+
* <div class="ug-modal__footer">
|
|
20
|
+
* <button class="ug-btn" data-ug-modal-close>Close</button>
|
|
21
|
+
* </div>
|
|
22
|
+
* </div>
|
|
23
|
+
* </div>
|
|
24
|
+
*/
|
|
25
|
+
(function () {
|
|
26
|
+
function openModal(id) {
|
|
27
|
+
var modal = document.getElementById(id);
|
|
28
|
+
if (!modal) return;
|
|
29
|
+
modal.classList.add('ug-modal--open');
|
|
30
|
+
document.body.classList.add('ug-modal-open');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function closeModal(modal) {
|
|
34
|
+
if (!modal) return;
|
|
35
|
+
modal.classList.remove('ug-modal--open');
|
|
36
|
+
// Only unlock body if no other modals are open
|
|
37
|
+
if (!document.querySelector('.ug-modal--open')) {
|
|
38
|
+
document.body.classList.remove('ug-modal-open');
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function closeAllModals() {
|
|
43
|
+
document.querySelectorAll('.ug-modal--open').forEach(function (m) {
|
|
44
|
+
m.classList.remove('ug-modal--open');
|
|
45
|
+
});
|
|
46
|
+
document.body.classList.remove('ug-modal-open');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function init() {
|
|
50
|
+
// Open triggers
|
|
51
|
+
document.addEventListener('click', function (e) {
|
|
52
|
+
var openTrigger = e.target.closest('[data-ug-modal-open]');
|
|
53
|
+
if (openTrigger) {
|
|
54
|
+
e.preventDefault();
|
|
55
|
+
openModal(openTrigger.getAttribute('data-ug-modal-open'));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Close triggers
|
|
60
|
+
var closeTrigger = e.target.closest('[data-ug-modal-close]');
|
|
61
|
+
if (closeTrigger) {
|
|
62
|
+
e.preventDefault();
|
|
63
|
+
var modal = closeTrigger.closest('.ug-modal');
|
|
64
|
+
closeModal(modal);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Close on Escape
|
|
69
|
+
document.addEventListener('keydown', function (e) {
|
|
70
|
+
if (e.key === 'Escape') {
|
|
71
|
+
closeAllModals();
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (document.readyState === 'loading') {
|
|
77
|
+
document.addEventListener('DOMContentLoaded', init);
|
|
78
|
+
} else {
|
|
79
|
+
init();
|
|
80
|
+
}
|
|
81
|
+
})();
|
package/src/js/scrollspy.js
CHANGED
|
@@ -1,87 +1,87 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unigrid Scrollspy
|
|
3
|
-
*
|
|
4
|
-
* Highlights navigation links based on which section is currently
|
|
5
|
-
* visible in the viewport using IntersectionObserver.
|
|
6
|
-
*
|
|
7
|
-
* Usage:
|
|
8
|
-
* <nav data-ug-scrollspy>
|
|
9
|
-
* <a class="ug-scrollspy__link" href="#intro">Intro</a>
|
|
10
|
-
* <a class="ug-scrollspy__link" href="#features">Features</a>
|
|
11
|
-
* </nav>
|
|
12
|
-
*
|
|
13
|
-
* <section id="intro">...</section>
|
|
14
|
-
* <section id="features">...</section>
|
|
15
|
-
*
|
|
16
|
-
* Options (via data attributes on [data-ug-scrollspy]):
|
|
17
|
-
* data-ug-scrollspy-offset="100" — top offset in px (default: 100)
|
|
18
|
-
* data-ug-scrollspy-class="custom" — active class (default: ug-scrollspy__link--active)
|
|
19
|
-
*/
|
|
20
|
-
(function () {
|
|
21
|
-
function init() {
|
|
22
|
-
document.querySelectorAll('[data-ug-scrollspy]').forEach(function (nav) {
|
|
23
|
-
var links = nav.querySelectorAll('.ug-scrollspy__link, [data-ug-spy]');
|
|
24
|
-
if (!links.length) return;
|
|
25
|
-
|
|
26
|
-
var offset = parseInt(nav.getAttribute('data-ug-scrollspy-offset') || '100', 10);
|
|
27
|
-
var activeClass = nav.getAttribute('data-ug-scrollspy-class') || 'ug-scrollspy__link--active';
|
|
28
|
-
|
|
29
|
-
// Collect target sections
|
|
30
|
-
var targets = [];
|
|
31
|
-
links.forEach(function (link) {
|
|
32
|
-
var href = link.getAttribute('href');
|
|
33
|
-
if (!href || href.charAt(0) !== '#') return;
|
|
34
|
-
var target = document.querySelector(href);
|
|
35
|
-
if (target) {
|
|
36
|
-
targets.push({ link: link, target: target });
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
if (!targets.length) return;
|
|
41
|
-
|
|
42
|
-
// Track which sections are visible
|
|
43
|
-
var visibleSections = new Set();
|
|
44
|
-
|
|
45
|
-
var observer = new IntersectionObserver(function (entries) {
|
|
46
|
-
entries.forEach(function (entry) {
|
|
47
|
-
if (entry.isIntersecting) {
|
|
48
|
-
visibleSections.add(entry.target.id);
|
|
49
|
-
} else {
|
|
50
|
-
visibleSections.delete(entry.target.id);
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
// Find the first visible section (in DOM order)
|
|
55
|
-
var activeId = null;
|
|
56
|
-
for (var i = 0; i < targets.length; i++) {
|
|
57
|
-
if (visibleSections.has(targets[i].target.id)) {
|
|
58
|
-
activeId = targets[i].target.id;
|
|
59
|
-
break;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Update active states
|
|
64
|
-
targets.forEach(function (item) {
|
|
65
|
-
if (item.target.id === activeId) {
|
|
66
|
-
item.link.classList.add(activeClass);
|
|
67
|
-
} else {
|
|
68
|
-
item.link.classList.remove(activeClass);
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
}, {
|
|
72
|
-
rootMargin: '-' + offset + 'px 0px -50% 0px',
|
|
73
|
-
threshold: 0
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
targets.forEach(function (item) {
|
|
77
|
-
observer.observe(item.target);
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (document.readyState === 'loading') {
|
|
83
|
-
document.addEventListener('DOMContentLoaded', init);
|
|
84
|
-
} else {
|
|
85
|
-
init();
|
|
86
|
-
}
|
|
87
|
-
})();
|
|
1
|
+
/**
|
|
2
|
+
* Unigrid Scrollspy
|
|
3
|
+
*
|
|
4
|
+
* Highlights navigation links based on which section is currently
|
|
5
|
+
* visible in the viewport using IntersectionObserver.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* <nav data-ug-scrollspy>
|
|
9
|
+
* <a class="ug-scrollspy__link" href="#intro">Intro</a>
|
|
10
|
+
* <a class="ug-scrollspy__link" href="#features">Features</a>
|
|
11
|
+
* </nav>
|
|
12
|
+
*
|
|
13
|
+
* <section id="intro">...</section>
|
|
14
|
+
* <section id="features">...</section>
|
|
15
|
+
*
|
|
16
|
+
* Options (via data attributes on [data-ug-scrollspy]):
|
|
17
|
+
* data-ug-scrollspy-offset="100" — top offset in px (default: 100)
|
|
18
|
+
* data-ug-scrollspy-class="custom" — active class (default: ug-scrollspy__link--active)
|
|
19
|
+
*/
|
|
20
|
+
(function () {
|
|
21
|
+
function init() {
|
|
22
|
+
document.querySelectorAll('[data-ug-scrollspy]').forEach(function (nav) {
|
|
23
|
+
var links = nav.querySelectorAll('.ug-scrollspy__link, [data-ug-spy]');
|
|
24
|
+
if (!links.length) return;
|
|
25
|
+
|
|
26
|
+
var offset = parseInt(nav.getAttribute('data-ug-scrollspy-offset') || '100', 10);
|
|
27
|
+
var activeClass = nav.getAttribute('data-ug-scrollspy-class') || 'ug-scrollspy__link--active';
|
|
28
|
+
|
|
29
|
+
// Collect target sections
|
|
30
|
+
var targets = [];
|
|
31
|
+
links.forEach(function (link) {
|
|
32
|
+
var href = link.getAttribute('href');
|
|
33
|
+
if (!href || href.charAt(0) !== '#') return;
|
|
34
|
+
var target = document.querySelector(href);
|
|
35
|
+
if (target) {
|
|
36
|
+
targets.push({ link: link, target: target });
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
if (!targets.length) return;
|
|
41
|
+
|
|
42
|
+
// Track which sections are visible
|
|
43
|
+
var visibleSections = new Set();
|
|
44
|
+
|
|
45
|
+
var observer = new IntersectionObserver(function (entries) {
|
|
46
|
+
entries.forEach(function (entry) {
|
|
47
|
+
if (entry.isIntersecting) {
|
|
48
|
+
visibleSections.add(entry.target.id);
|
|
49
|
+
} else {
|
|
50
|
+
visibleSections.delete(entry.target.id);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Find the first visible section (in DOM order)
|
|
55
|
+
var activeId = null;
|
|
56
|
+
for (var i = 0; i < targets.length; i++) {
|
|
57
|
+
if (visibleSections.has(targets[i].target.id)) {
|
|
58
|
+
activeId = targets[i].target.id;
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Update active states
|
|
64
|
+
targets.forEach(function (item) {
|
|
65
|
+
if (item.target.id === activeId) {
|
|
66
|
+
item.link.classList.add(activeClass);
|
|
67
|
+
} else {
|
|
68
|
+
item.link.classList.remove(activeClass);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}, {
|
|
72
|
+
rootMargin: '-' + offset + 'px 0px -50% 0px',
|
|
73
|
+
threshold: 0
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
targets.forEach(function (item) {
|
|
77
|
+
observer.observe(item.target);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (document.readyState === 'loading') {
|
|
83
|
+
document.addEventListener('DOMContentLoaded', init);
|
|
84
|
+
} else {
|
|
85
|
+
init();
|
|
86
|
+
}
|
|
87
|
+
})();
|
package/src/js/tabs.js
CHANGED
|
@@ -1,58 +1,58 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unigrid Tabs
|
|
3
|
-
*
|
|
4
|
-
* Switches active tab link and panel on click.
|
|
5
|
-
* Auto-initializes on DOMContentLoaded.
|
|
6
|
-
*
|
|
7
|
-
* Usage:
|
|
8
|
-
* <div class="ug-tabs" data-ug-tabs>
|
|
9
|
-
* <ul class="ug-tabs__nav">
|
|
10
|
-
* <li class="ug-tabs__item">
|
|
11
|
-
* <button class="ug-tabs__link ug-tabs__link--active" data-ug-tab="tab1">Tab 1</button>
|
|
12
|
-
* </li>
|
|
13
|
-
* </ul>
|
|
14
|
-
* <div class="ug-tabs__content">
|
|
15
|
-
* <div class="ug-tabs__panel ug-tabs__panel--active" data-ug-panel="tab1">...</div>
|
|
16
|
-
* </div>
|
|
17
|
-
* </div>
|
|
18
|
-
*/
|
|
19
|
-
(function () {
|
|
20
|
-
function init() {
|
|
21
|
-
document.addEventListener('click', function (e) {
|
|
22
|
-
var link = e.target.closest('[data-ug-tab]');
|
|
23
|
-
if (!link) return;
|
|
24
|
-
|
|
25
|
-
e.preventDefault();
|
|
26
|
-
|
|
27
|
-
var tabs = link.closest('.ug-tabs');
|
|
28
|
-
if (!tabs) return;
|
|
29
|
-
|
|
30
|
-
var target = link.getAttribute('data-ug-tab');
|
|
31
|
-
|
|
32
|
-
// Deactivate all links
|
|
33
|
-
tabs.querySelectorAll('.ug-tabs__link').forEach(function (l) {
|
|
34
|
-
l.classList.remove('ug-tabs__link--active');
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
// Deactivate all panels
|
|
38
|
-
tabs.querySelectorAll('.ug-tabs__panel').forEach(function (p) {
|
|
39
|
-
p.classList.remove('ug-tabs__panel--active');
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
// Activate clicked link
|
|
43
|
-
link.classList.add('ug-tabs__link--active');
|
|
44
|
-
|
|
45
|
-
// Activate matching panel
|
|
46
|
-
var panel = tabs.querySelector('[data-ug-panel="' + target + '"]');
|
|
47
|
-
if (panel) {
|
|
48
|
-
panel.classList.add('ug-tabs__panel--active');
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (document.readyState === 'loading') {
|
|
54
|
-
document.addEventListener('DOMContentLoaded', init);
|
|
55
|
-
} else {
|
|
56
|
-
init();
|
|
57
|
-
}
|
|
58
|
-
})();
|
|
1
|
+
/**
|
|
2
|
+
* Unigrid Tabs
|
|
3
|
+
*
|
|
4
|
+
* Switches active tab link and panel on click.
|
|
5
|
+
* Auto-initializes on DOMContentLoaded.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* <div class="ug-tabs" data-ug-tabs>
|
|
9
|
+
* <ul class="ug-tabs__nav">
|
|
10
|
+
* <li class="ug-tabs__item">
|
|
11
|
+
* <button class="ug-tabs__link ug-tabs__link--active" data-ug-tab="tab1">Tab 1</button>
|
|
12
|
+
* </li>
|
|
13
|
+
* </ul>
|
|
14
|
+
* <div class="ug-tabs__content">
|
|
15
|
+
* <div class="ug-tabs__panel ug-tabs__panel--active" data-ug-panel="tab1">...</div>
|
|
16
|
+
* </div>
|
|
17
|
+
* </div>
|
|
18
|
+
*/
|
|
19
|
+
(function () {
|
|
20
|
+
function init() {
|
|
21
|
+
document.addEventListener('click', function (e) {
|
|
22
|
+
var link = e.target.closest('[data-ug-tab]');
|
|
23
|
+
if (!link) return;
|
|
24
|
+
|
|
25
|
+
e.preventDefault();
|
|
26
|
+
|
|
27
|
+
var tabs = link.closest('.ug-tabs');
|
|
28
|
+
if (!tabs) return;
|
|
29
|
+
|
|
30
|
+
var target = link.getAttribute('data-ug-tab');
|
|
31
|
+
|
|
32
|
+
// Deactivate all links
|
|
33
|
+
tabs.querySelectorAll('.ug-tabs__link').forEach(function (l) {
|
|
34
|
+
l.classList.remove('ug-tabs__link--active');
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// Deactivate all panels
|
|
38
|
+
tabs.querySelectorAll('.ug-tabs__panel').forEach(function (p) {
|
|
39
|
+
p.classList.remove('ug-tabs__panel--active');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Activate clicked link
|
|
43
|
+
link.classList.add('ug-tabs__link--active');
|
|
44
|
+
|
|
45
|
+
// Activate matching panel
|
|
46
|
+
var panel = tabs.querySelector('[data-ug-panel="' + target + '"]');
|
|
47
|
+
if (panel) {
|
|
48
|
+
panel.classList.add('ug-tabs__panel--active');
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (document.readyState === 'loading') {
|
|
54
|
+
document.addEventListener('DOMContentLoaded', init);
|
|
55
|
+
} else {
|
|
56
|
+
init();
|
|
57
|
+
}
|
|
58
|
+
})();
|
package/src/scss/_accordion.scss
CHANGED
|
@@ -1,123 +1,123 @@
|
|
|
1
|
-
// ==========================================================================
|
|
2
|
-
// Unigrid CSS Framework — Accordion (BEM)
|
|
3
|
-
//
|
|
4
|
-
// Pure HTML/CSS accordion using <details>/<summary>. No JS required.
|
|
5
|
-
// Caret rotates when open.
|
|
6
|
-
//
|
|
7
|
-
// Block: .ug-accordion
|
|
8
|
-
// Elements: __item, __header, __caret, __body
|
|
9
|
-
// Modifiers: --bordered, --flush, --dark
|
|
10
|
-
// ==========================================================================
|
|
11
|
-
|
|
12
|
-
@use "variables" as *;
|
|
13
|
-
@use "mixins" as *;
|
|
14
|
-
|
|
15
|
-
.ug-accordion {
|
|
16
|
-
|
|
17
|
-
// ---- Item (details element) ----
|
|
18
|
-
&__item {
|
|
19
|
-
border-bottom: 1px solid $ug-light-gray;
|
|
20
|
-
|
|
21
|
-
&[open] > .ug-accordion__header .ug-accordion__caret {
|
|
22
|
-
transform: rotate(-135deg);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// ---- Header (summary element) ----
|
|
27
|
-
&__header {
|
|
28
|
-
display: flex;
|
|
29
|
-
align-items: center;
|
|
30
|
-
justify-content: space-between;
|
|
31
|
-
padding: calc(var(--ug-leading) * 0.5) 0;
|
|
32
|
-
@include ug-font-size("base");
|
|
33
|
-
@include ug-font-weight("bold");
|
|
34
|
-
@include ug-rhythm-line-height(1);
|
|
35
|
-
cursor: pointer;
|
|
36
|
-
list-style: none;
|
|
37
|
-
user-select: none;
|
|
38
|
-
transition: color 0.15s;
|
|
39
|
-
|
|
40
|
-
&::-webkit-details-marker {
|
|
41
|
-
display: none;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
&::marker {
|
|
45
|
-
content: "";
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
&:hover {
|
|
49
|
-
color: $ug-medium-gray;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// ---- Caret ----
|
|
54
|
-
&__caret {
|
|
55
|
-
display: inline-block;
|
|
56
|
-
width: 0.6em;
|
|
57
|
-
height: 0.6em;
|
|
58
|
-
border-right: 2px solid currentColor;
|
|
59
|
-
border-bottom: 2px solid currentColor;
|
|
60
|
-
transform: rotate(45deg);
|
|
61
|
-
transition: transform 0.2s;
|
|
62
|
-
flex-shrink: 0;
|
|
63
|
-
margin-left: var(--ug-leading);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// ---- Body ----
|
|
67
|
-
&__body {
|
|
68
|
-
padding: 0 0 var(--ug-leading) 0;
|
|
69
|
-
@include ug-font-size("sm");
|
|
70
|
-
@include ug-rhythm-line-height(1);
|
|
71
|
-
color: $ug-dark-gray;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// ==============================
|
|
75
|
-
// Modifiers
|
|
76
|
-
// ==============================
|
|
77
|
-
|
|
78
|
-
// Bordered: border on all sides
|
|
79
|
-
&--bordered {
|
|
80
|
-
border: 1px solid $ug-light-gray;
|
|
81
|
-
|
|
82
|
-
.ug-accordion__item {
|
|
83
|
-
border-bottom: 1px solid $ug-light-gray;
|
|
84
|
-
|
|
85
|
-
&:last-child {
|
|
86
|
-
border-bottom: none;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
.ug-accordion__header {
|
|
91
|
-
padding: calc(var(--ug-leading) * 0.5) var(--ug-leading);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
.ug-accordion__body {
|
|
95
|
-
padding: 0 var(--ug-leading) var(--ug-leading);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Flush: no borders at all
|
|
100
|
-
&--flush {
|
|
101
|
-
.ug-accordion__item {
|
|
102
|
-
border-bottom: none;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Dark
|
|
107
|
-
&--dark {
|
|
108
|
-
background-color: $ug-black;
|
|
109
|
-
color: $ug-white;
|
|
110
|
-
|
|
111
|
-
.ug-accordion__item {
|
|
112
|
-
border-bottom-color: rgba(255, 255, 255, 0.1);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
.ug-accordion__header:hover {
|
|
116
|
-
color: rgba(255, 255, 255, 0.6);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
.ug-accordion__body {
|
|
120
|
-
color: rgba(255, 255, 255, 0.7);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
1
|
+
// ==========================================================================
|
|
2
|
+
// Unigrid CSS Framework — Accordion (BEM)
|
|
3
|
+
//
|
|
4
|
+
// Pure HTML/CSS accordion using <details>/<summary>. No JS required.
|
|
5
|
+
// Caret rotates when open.
|
|
6
|
+
//
|
|
7
|
+
// Block: .ug-accordion
|
|
8
|
+
// Elements: __item, __header, __caret, __body
|
|
9
|
+
// Modifiers: --bordered, --flush, --dark
|
|
10
|
+
// ==========================================================================
|
|
11
|
+
|
|
12
|
+
@use "variables" as *;
|
|
13
|
+
@use "mixins" as *;
|
|
14
|
+
|
|
15
|
+
.ug-accordion {
|
|
16
|
+
|
|
17
|
+
// ---- Item (details element) ----
|
|
18
|
+
&__item {
|
|
19
|
+
border-bottom: 1px solid $ug-light-gray;
|
|
20
|
+
|
|
21
|
+
&[open] > .ug-accordion__header .ug-accordion__caret {
|
|
22
|
+
transform: rotate(-135deg);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// ---- Header (summary element) ----
|
|
27
|
+
&__header {
|
|
28
|
+
display: flex;
|
|
29
|
+
align-items: center;
|
|
30
|
+
justify-content: space-between;
|
|
31
|
+
padding: calc(var(--ug-leading) * 0.5) 0;
|
|
32
|
+
@include ug-font-size("base");
|
|
33
|
+
@include ug-font-weight("bold");
|
|
34
|
+
@include ug-rhythm-line-height(1);
|
|
35
|
+
cursor: pointer;
|
|
36
|
+
list-style: none;
|
|
37
|
+
user-select: none;
|
|
38
|
+
transition: color 0.15s;
|
|
39
|
+
|
|
40
|
+
&::-webkit-details-marker {
|
|
41
|
+
display: none;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
&::marker {
|
|
45
|
+
content: "";
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
&:hover {
|
|
49
|
+
color: $ug-medium-gray;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ---- Caret ----
|
|
54
|
+
&__caret {
|
|
55
|
+
display: inline-block;
|
|
56
|
+
width: 0.6em;
|
|
57
|
+
height: 0.6em;
|
|
58
|
+
border-right: 2px solid currentColor;
|
|
59
|
+
border-bottom: 2px solid currentColor;
|
|
60
|
+
transform: rotate(45deg);
|
|
61
|
+
transition: transform 0.2s;
|
|
62
|
+
flex-shrink: 0;
|
|
63
|
+
margin-left: var(--ug-leading);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ---- Body ----
|
|
67
|
+
&__body {
|
|
68
|
+
padding: 0 0 var(--ug-leading) 0;
|
|
69
|
+
@include ug-font-size("sm");
|
|
70
|
+
@include ug-rhythm-line-height(1);
|
|
71
|
+
color: $ug-dark-gray;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ==============================
|
|
75
|
+
// Modifiers
|
|
76
|
+
// ==============================
|
|
77
|
+
|
|
78
|
+
// Bordered: border on all sides
|
|
79
|
+
&--bordered {
|
|
80
|
+
border: 1px solid $ug-light-gray;
|
|
81
|
+
|
|
82
|
+
.ug-accordion__item {
|
|
83
|
+
border-bottom: 1px solid $ug-light-gray;
|
|
84
|
+
|
|
85
|
+
&:last-child {
|
|
86
|
+
border-bottom: none;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.ug-accordion__header {
|
|
91
|
+
padding: calc(var(--ug-leading) * 0.5) var(--ug-leading);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.ug-accordion__body {
|
|
95
|
+
padding: 0 var(--ug-leading) var(--ug-leading);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Flush: no borders at all
|
|
100
|
+
&--flush {
|
|
101
|
+
.ug-accordion__item {
|
|
102
|
+
border-bottom: none;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Dark
|
|
107
|
+
&--dark {
|
|
108
|
+
background-color: $ug-black;
|
|
109
|
+
color: $ug-white;
|
|
110
|
+
|
|
111
|
+
.ug-accordion__item {
|
|
112
|
+
border-bottom-color: rgba(255, 255, 255, 0.1);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.ug-accordion__header:hover {
|
|
116
|
+
color: rgba(255, 255, 255, 0.6);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.ug-accordion__body {
|
|
120
|
+
color: rgba(255, 255, 255, 0.7);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|