maverick-wave 3.3.0 → 3.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/.claude/skills/maverick-wave/SKILL.md +208 -0
- package/.claude/skills/maverick-wave/examples/angular-form.md +275 -0
- package/.claude/skills/maverick-wave/examples/angular-list-page.md +304 -0
- package/.claude/skills/maverick-wave/examples/angular-services.md +348 -0
- package/.claude/skills/maverick-wave/examples/static-landing-page.md +362 -0
- package/.claude/skills/maverick-wave/references/components.md +812 -0
- package/.claude/skills/maverick-wave/references/forms.md +289 -0
- package/.claude/skills/maverick-wave/references/javascript.md +70 -0
- package/.claude/skills/maverick-wave/references/layout.md +300 -0
- package/.claude/skills/maverick-wave/references/theming.md +192 -0
- package/.github/workflows/ci.yml +41 -0
- package/CHANGELOG.md +13 -0
- package/README.md +115 -21
- package/index.html +15 -9
- package/maverick-wave.min.css +1 -1
- package/maverick-wave.min.js +1 -1
- package/package.json +3 -1
- package/scripts/verify.js +137 -0
- package/src/js/main.js +39 -11
- package/src/partials/accordions-container.html +22 -27
- package/src/partials/alerts-container.html +26 -0
- package/src/partials/avatars-container.html +22 -0
- package/src/partials/buttons-container.html +11 -15
- package/src/partials/cards-container.html +8 -8
- package/src/partials/colors-container.html +33 -20
- package/src/partials/documentation-container.html +3 -0
- package/src/partials/form-field-container.html +16 -12
- package/src/partials/get-started-container.html +93 -35
- package/src/partials/header-utilities-container.html +64 -6
- package/src/partials/input-group-container.html +5 -3
- package/src/partials/page-header-container.html +78 -0
- package/src/partials/tables-container.html +130 -0
- package/src/partials/tabs-container.html +20 -16
- package/src/partials/tags-container.html +55 -1
- package/src/scss/abstracts/_index.scss +4 -1
- package/src/scss/abstracts/_variables.scss +128 -106
- package/src/scss/base/_base.scss +32 -136
- package/src/scss/base/_reset.scss +1 -1
- package/src/scss/base/_typography.scss +0 -92
- package/src/scss/components/_accordions.scss +3 -3
- package/src/scss/components/_avatars.scss +28 -1
- package/src/scss/components/_blog-post.scss +1 -1
- package/src/scss/components/_button-bar.scss +6 -6
- package/src/scss/components/_buttons.scss +33 -10
- package/src/scss/components/_cards.scss +7 -7
- package/src/scss/components/_coming-soon.scss +4 -4
- package/src/scss/components/_gallery.scss +2 -2
- package/src/scss/components/_index.scss +1 -0
- package/src/scss/components/_info.scss +20 -3
- package/src/scss/components/_lists.scss +11 -10
- package/src/scss/components/_modals.scss +14 -7
- package/src/scss/components/_pagination.scss +3 -3
- package/src/scss/components/_panels.scss +4 -4
- package/src/scss/components/_progress.scss +1 -1
- package/src/scss/components/_ratings.scss +1 -1
- package/src/scss/components/_spinners.scss +2 -2
- package/src/scss/components/_stepper.scss +3 -2
- package/src/scss/components/_tables.scss +42 -1
- package/src/scss/components/_tabs.scss +5 -5
- package/src/scss/components/_tags.scss +43 -27
- package/src/scss/components/_tiles.scss +3 -3
- package/src/scss/components/_timelines.scss +2 -2
- package/src/scss/components/_toasts.scss +92 -0
- package/src/scss/form-elements/_form.scss +11 -3
- package/src/scss/form-elements/_input.scss +24 -0
- package/src/scss/form-elements/_toggle.scss +1 -1
- package/src/scss/layout/_footer.scss +4 -4
- package/src/scss/layout/_header.scss +219 -59
- package/src/scss/layout/_index.scss +1 -0
- package/src/scss/layout/_main.scss +1 -1
- package/src/scss/layout/_page-header.scss +48 -0
- package/src/scss/layout/_section.scss +15 -14
- package/src/scss/main.scss +4 -0
- package/src/scss/utilities/_flex.scss +4 -0
- package/src/scss/utilities/_index.scss +1 -0
- package/src/scss/utilities/_text.scss +105 -0
- package/.claude/commands/mw.md +0 -595
package/maverick-wave.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(){"use strict";function e(){document.querySelectorAll(".color-swatch").forEach(e=>{const t=function(e){if(!e||"transparent"===e)return"#000000";
|
|
1
|
+
!function(){"use strict";function e(){document.querySelectorAll(".color-swatch").forEach(e=>{const t=function(e){if(!e||"transparent"===e)return"#000000";const t=e=>Math.max(0,Math.min(255,Math.round(e))).toString(16).padStart(2,"0"),c=e.match(/color\(srgb\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)(?:\s*\/\s*([\d.]+))?\)/);if(c){const e="#"+t(255*c[1])+t(255*c[2])+t(255*c[3]),o=void 0===c[4]?1:parseFloat(c[4]);return(o<1?`${e} / ${o}`:e).toUpperCase()}const o=e.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);if(!o)return e;const n="#"+t(o[1])+t(o[2])+t(o[3]),s=void 0===o[4]?1:parseFloat(o[4]);return(s<1?`${n} / ${s}`:n).toUpperCase()}(window.getComputedStyle(e).backgroundColor),c=e.parentElement.querySelector(".mw-text-muted");c&&(c.textContent=t)})}document.addEventListener("DOMContentLoaded",function(){!function(){const e=document.querySelector(".mw-gallery-track");if(e){const t=document.querySelector(".mw-gallery-dots"),c=e.children,o=document.querySelector(".mw-gallery-desc"),n=document.querySelector(".mw-gallery-navi-prev"),s=document.querySelector(".mw-gallery-navi-next"),l=document.querySelector(".mw-gallery");let r=0;function i(){const t=l.offsetWidth;e.style.transform=`translateX(-${r*t}px)`}function a(e){const t=c.length;r=(e+t)%t,i(),document.querySelectorAll(".mw-gallery-dot").forEach((e,t)=>{e.classList.toggle("mw-active",t===r)}),o.textContent=c[r].dataset.desc}function d(){for(let e=0;e<c.length;e++){const c=document.createElement("span");c.className="mw-gallery-dot"+(0===e?" mw-active":""),c.addEventListener("click",()=>a(e)),t.appendChild(c)}}n.addEventListener("click",()=>a(r-1)),s.addEventListener("click",()=>a(r+1)),window.addEventListener("resize",i);let u=0;e.addEventListener("touchstart",e=>u=e.touches[0].clientX),e.addEventListener("touchend",e=>{const t=e.changedTouches[0].clientX-u;t>50&&a(r-1),t<-50&&a(r+1)}),d(),i()}}(),function(){const t=document.querySelector(".mw-theme-toggle");if(!t)return;const c=document.body,o=t.querySelector(".mw-theme-toggle-slider i"),n=getComputedStyle(document.documentElement).getPropertyValue("--mw-internal-theme-mode").trim()||"switchable";if("switchable"!==n)return console.log(`Theme mode fixed to: ${n}. Disabling toggle.`),o&&(o.className="light"===n?"fas fa-sun":"fas fa-moon"),"light"===n?t.classList.add("active"):t.classList.remove("active"),t.style.opacity="0.4",t.style.pointerEvents="none",t.style.cursor="default",t.setAttribute("aria-disabled","true"),localStorage.removeItem("mw-theme"),void("dark"===n&&c.classList.remove("mw-theme-light"));let s="light"===localStorage.getItem("mw-theme");const l=e=>{c.classList.toggle("mw-theme-light",e),t.classList.toggle("active",e),o&&(o.className=e?"fas fa-sun":"fas fa-moon")};l(s),t.addEventListener("click",()=>{s=!s,l(s),localStorage.setItem("mw-theme",s?"light":"dark"),setTimeout(e,400)})}(),e(),document.querySelectorAll(".mw-accordion-header").forEach(e=>{e.addEventListener("click",function(){this.classList.toggle("active");const e=this.nextElementSibling;e&&e.classList.toggle("active")})}),function(){const e=document.querySelector(".mw-menu-btn"),t=document.querySelector(".mw-navbar");if(!e||!t)return;function c(){e.classList.remove("open"),t.classList.remove("open")}function o(c){c.preventDefault(),c.stopPropagation(),e.classList.toggle("open"),t.classList.toggle("open")}e.addEventListener("click",o),e.addEventListener("touchstart",o,{passive:!1}),document.addEventListener("click",function(o){t.classList.contains("open")&&(t.contains(o.target)||e.contains(o.target)||c())}),document.addEventListener("keydown",function(e){"Escape"===e.key&&c()})}(),function(){const e=document.querySelectorAll(".mw-progress-fill");if(!e.length)return;const t=new IntersectionObserver((e,t)=>{e.forEach(e=>{if(!e.isIntersecting)return;const c=e.target,o=c.dataset.value||0;c.style.width=o+"%",t.unobserve(c)})},{root:null,threshold:.2});e.forEach(e=>t.observe(e))}(),document.querySelectorAll('a[href^="#"]').forEach(e=>{e.addEventListener("click",function(e){const t=this.getAttribute("href");if("#"===t)return;if(!document.querySelector(t))return;const c=document.querySelector(".mw-menu-btn"),o=document.querySelector(".mw-navbar");c&&o&&(c.classList.remove("open"),o.classList.remove("open"))})}),function(){const e=document.querySelectorAll("section[id]"),t=document.querySelectorAll(".mw-navbar-link");if(0===e.length||0===t.length)return;window.addEventListener("scroll",function(e,t){let c;return function(){const o=this,n=arguments;clearTimeout(c),c=setTimeout(()=>e.apply(o,n),t)}}(function(){let c="";e.forEach(e=>{const t=e.offsetTop-100,o=e.clientHeight;scrollY>=t&&scrollY<t+o&&(c=e.getAttribute("id"))}),t.forEach(e=>{e.classList.remove("active");const t=e.getAttribute("href");if(t){const o=t.indexOf("#");if(-1!==o){t.substring(o+1)===c&&e.classList.add("active")}}})},100))}(),document.querySelectorAll(".mw-tabs-nav-item").forEach(e=>{e.addEventListener("click",function(){const e=this.closest(".mw-tabs");if(!e)return;e.querySelectorAll(".mw-tabs-nav-item").forEach(e=>{e.classList.remove("active")}),this.classList.add("active");const t=this.getAttribute("data-tab");if(!t)return;e.querySelectorAll(".mw-tabs-panel").forEach(e=>{e.classList.remove("active")});const c=document.getElementById(t);c&&c.classList.add("active")})}),document.querySelectorAll(".mw-alert-close").forEach(e=>{e.addEventListener("click",function(){const e=this.closest(".mw-alert");e&&(e.classList.add("mw-alert-closing"),setTimeout(()=>{e.classList.add("mw-alert-closed")},300))})}),function(){const e=document.querySelector(".mw-localhost-indicator-activated"),t=document.querySelector(".mw-header");if(e){if("localhost"===window.location.hostname||"127.0.0.1"===window.location.hostname||window.location.hostname.includes("192.168.")){const e=document.createElement("div");e.className="mw-localhost-indicator-pulse",t.prepend(e)}}}(),document.querySelectorAll(".mw-slider-container").forEach(e=>{const t=e.querySelector(".mw-slider"),c=e.querySelector(".mw-slider-value");if(!t||!c)return;const o=()=>{const e=Number(t.value),o=Number(t.max)||100,n=Math.round(e/o*100);t.style.setProperty("--value",n+"%"),c.classList.contains("mw-slider-numeric")?c.setAttribute("data-value",e):c.setAttribute("data-value",n)};t.addEventListener("input",o),o()}),document.querySelectorAll(".mw-modal-close").forEach(e=>{e.addEventListener("click",function(){const e=this.closest(".mw-modal-overlay");e&&e.classList.remove("mw-modal-open")})}),function(){const e=document.getElementById("login-button");e&&e.addEventListener("click",function(){const e=this.querySelector("i");e.classList.contains("fa-lock")?(e.classList.remove("fa-lock"),e.classList.add("fa-lock-open")):(e.classList.remove("fa-lock-open"),e.classList.add("fa-lock"))})}(),document.querySelectorAll(".mw-image-slider").forEach(e=>{const t=e.querySelectorAll(".mw-image-slider-overlay-image"),c=e.querySelectorAll("button[data-index]");if(!t.length||!c.length)return;let o=0;function n(){t.forEach(e=>{const t=parseInt(e.dataset.index);e.classList.toggle("active",t===o)}),c.forEach(e=>{const t=parseInt(e.dataset.index);e.classList.toggle("active",t===o)})}function s(e){o=e,n()}c.forEach(e=>{e.addEventListener("click",()=>{s(parseInt(e.dataset.index))})}),n()}),document.querySelectorAll(".mw-item-list-checkbox, .mw-item-list-checkbox-scroll").forEach(e=>{e.querySelectorAll("li").forEach(e=>{const t=e.querySelector('input[type="checkbox"]'),c=e.querySelector(".mw-checkbox");t&&c&&(t.checked&&e.classList.add("mw-selected"),e.addEventListener("click",function(e){e.target!==t&&e.target.closest(".mw-checkbox")!==c&&toggleCheckbox(this)}),t.addEventListener("change",function(){const e=this.closest("li");this.checked?e.classList.add("mw-selected"):e.classList.remove("mw-selected"),e.dispatchEvent(new CustomEvent("checkboxToggle",{detail:{checked:this.checked,item:e}}))}),c.addEventListener("click",function(e){setTimeout(()=>{const e=this.closest("li");this.querySelector('input[type="checkbox"]').checked?e.classList.add("mw-selected"):e.classList.remove("mw-selected")},0)}))})}),document.addEventListener("checkboxToggle",function(e){console.log("Checkbox toggled:",e.detail.checked,e.detail.item)})}),window.toggleCheckbox=function(e){const t=e.querySelector('input[type="checkbox"]');if(!t)return;const c=t.checked;t.checked=!c,t.checked?e.classList.add("mw-selected"):e.classList.remove("mw-selected"),e.dispatchEvent(new CustomEvent("checkboxToggle",{detail:{checked:t.checked,item:e}}))}}();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "maverick-wave",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.2",
|
|
4
4
|
"config": {
|
|
5
5
|
"version_short": "3.3"
|
|
6
6
|
},
|
|
@@ -10,9 +10,11 @@
|
|
|
10
10
|
"scripts": {
|
|
11
11
|
"clean": "gulp clean",
|
|
12
12
|
"format": "prettier --write \"**/*.{scss,js,json,html,md}\"",
|
|
13
|
+
"format:check": "prettier --check \"**/*.{scss,js,json,html,md}\"",
|
|
13
14
|
"showcase": "http-server -c-1 -p 8888 dist",
|
|
14
15
|
"start": "gulp",
|
|
15
16
|
"build": "gulp clean && gulp build",
|
|
17
|
+
"verify": "node scripts/verify.js",
|
|
16
18
|
"release": "gulp release"
|
|
17
19
|
},
|
|
18
20
|
"repository": {
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Consistency checks between the built CSS and everything that references it.
|
|
4
|
+
* Runs against dist/, so `npm run build` has to happen first.
|
|
5
|
+
*
|
|
6
|
+
* 1. every var(--mw-*) has a definition
|
|
7
|
+
* 2. every --mw-* definition is used somewhere
|
|
8
|
+
* 3. every mw-* class in the markup exists in the built CSS
|
|
9
|
+
*
|
|
10
|
+
* Sources are scanned rather than hard-coded so a new partial is covered
|
|
11
|
+
* automatically. Exits 1 on any error; warnings never fail the build.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const fs = require('fs');
|
|
15
|
+
const path = require('path');
|
|
16
|
+
|
|
17
|
+
const ROOT = path.join(__dirname, '..');
|
|
18
|
+
const CSS = path.join(ROOT, 'dist', 'maverick-wave.min.css');
|
|
19
|
+
const HTML = path.join(ROOT, 'dist', 'index.html');
|
|
20
|
+
const JS = path.join(ROOT, 'src', 'js', 'main.js');
|
|
21
|
+
|
|
22
|
+
// Everything that documents classes: the slash command plus every markdown file
|
|
23
|
+
// of the maverick-wave skill. Collected by walking the tree, so a new reference
|
|
24
|
+
// or example file is covered without touching this list.
|
|
25
|
+
const DOCS = [
|
|
26
|
+
path.join(ROOT, '.claude', 'commands', 'mw.md'),
|
|
27
|
+
...markdownFiles(path.join(ROOT, '.claude', 'skills')),
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
// Tokens read by JavaScript or reserved for consumers, so "unused in CSS" is fine
|
|
31
|
+
const TOKEN_ALLOWLIST = new Set(['--mw-internal-theme-mode']);
|
|
32
|
+
|
|
33
|
+
// Classes that exist only as JS hooks or are applied by the host application
|
|
34
|
+
const CLASS_ALLOWLIST = new Set([]);
|
|
35
|
+
|
|
36
|
+
const read = (p) => (fs.existsSync(p) ? fs.readFileSync(p, 'utf8') : null);
|
|
37
|
+
const all = (str, re) => [...str.matchAll(re)].map((m) => m[1]);
|
|
38
|
+
|
|
39
|
+
function markdownFiles(dir) {
|
|
40
|
+
if (!fs.existsSync(dir)) return [];
|
|
41
|
+
return fs.readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
|
|
42
|
+
const full = path.join(dir, entry.name);
|
|
43
|
+
if (entry.isDirectory()) return markdownFiles(full);
|
|
44
|
+
return entry.name.endsWith('.md') ? [full] : [];
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const errors = [];
|
|
49
|
+
const warnings = [];
|
|
50
|
+
|
|
51
|
+
const css = read(CSS);
|
|
52
|
+
const html = read(HTML);
|
|
53
|
+
if (!css || !html) {
|
|
54
|
+
console.error(
|
|
55
|
+
'dist/ is missing or incomplete — run `npm run build` before `npm run verify`.'
|
|
56
|
+
);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
const js = read(JS) || '';
|
|
60
|
+
const docs = DOCS.map(read).filter(Boolean).join('\n');
|
|
61
|
+
|
|
62
|
+
// --- 1 + 2: custom properties ---------------------------------------------
|
|
63
|
+
|
|
64
|
+
const tokensDefined = new Set(all(css, /(--mw-[a-z0-9-]+)\s*:/g));
|
|
65
|
+
const tokensUsed = new Set([
|
|
66
|
+
...all(css, /var\((--mw-[a-z0-9-]+)/g),
|
|
67
|
+
...all(html, /var\((--mw-[a-z0-9-]+)/g),
|
|
68
|
+
...all(js, /(--mw-[a-z0-9-]+)/g),
|
|
69
|
+
]);
|
|
70
|
+
|
|
71
|
+
for (const t of [...tokensUsed].sort()) {
|
|
72
|
+
if (!tokensDefined.has(t)) {
|
|
73
|
+
errors.push(`token referenced but never defined: var(${t})`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
for (const t of [...tokensDefined].sort()) {
|
|
77
|
+
if (!tokensUsed.has(t) && !TOKEN_ALLOWLIST.has(t)) {
|
|
78
|
+
errors.push(
|
|
79
|
+
`token defined but never used: ${t} — overriding it would do nothing`
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// --- 3: classes ------------------------------------------------------------
|
|
85
|
+
|
|
86
|
+
const classesInCss = new Set(all(css, /\.(mw-[a-z0-9-]+)/g));
|
|
87
|
+
|
|
88
|
+
// Classes the JS adds at runtime, or queries as a hook, count as legitimate
|
|
89
|
+
// targets — including selector strings like '.mw-foo' and '[class~="mw-foo"]'
|
|
90
|
+
const classesInJs = new Set(all(js, /\.?(mw-[a-z0-9-]+)/g));
|
|
91
|
+
|
|
92
|
+
const classesInMarkup = new Map(); // class -> where it was seen
|
|
93
|
+
for (const attr of html.matchAll(/class\s*=\s*"([^"]*)"/g)) {
|
|
94
|
+
for (const c of attr[1].split(/\s+/)) {
|
|
95
|
+
if (c.startsWith('mw-') && !classesInMarkup.has(c)) {
|
|
96
|
+
classesInMarkup.set(c, 'showcase');
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// The docs name classes as `mw-foo` in prose and code fences. A trailing hyphen
|
|
101
|
+
// means a family was written as a stem (`mw-btn-mini-` + variants), never a real
|
|
102
|
+
// class — skip those instead of reporting them as missing.
|
|
103
|
+
for (const c of all(docs, /[`."'\s](mw-[a-z0-9-]+)/g)) {
|
|
104
|
+
if (c.endsWith('-')) continue;
|
|
105
|
+
if (!classesInMarkup.has(c)) classesInMarkup.set(c, 'docs');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
for (const [c, where] of [...classesInMarkup].sort()) {
|
|
109
|
+
if (classesInCss.has(c) || classesInJs.has(c) || CLASS_ALLOWLIST.has(c)) {
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
errors.push(`class used in ${where} but not generated by the CSS: .${c}`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Informational: framework classes the showcase never demonstrates
|
|
116
|
+
const undocumented = [...classesInCss].filter(
|
|
117
|
+
(c) => !classesInMarkup.has(c) && !classesInJs.has(c)
|
|
118
|
+
);
|
|
119
|
+
if (undocumented.length) {
|
|
120
|
+
warnings.push(
|
|
121
|
+
`${undocumented.length} classes exist in the CSS but are not shown in the showcase`
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// --- report ----------------------------------------------------------------
|
|
126
|
+
|
|
127
|
+
const label = (n, s) => `${n} ${s}${n === 1 ? '' : 's'}`;
|
|
128
|
+
|
|
129
|
+
for (const w of warnings) console.log(` warn ${w}`);
|
|
130
|
+
for (const e of errors) console.error(` ERROR ${e}`);
|
|
131
|
+
|
|
132
|
+
console.log(
|
|
133
|
+
`\nverify: ${tokensDefined.size} tokens, ${classesInCss.size} classes checked — ` +
|
|
134
|
+
(errors.length ? `${label(errors.length, 'error')}` : 'clean')
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
process.exit(errors.length ? 1 : 0);
|
package/src/js/main.js
CHANGED
|
@@ -268,23 +268,35 @@
|
|
|
268
268
|
}
|
|
269
269
|
|
|
270
270
|
function rgbToHex(rgb) {
|
|
271
|
-
// Check if the color is in RGB/RGBA format
|
|
272
271
|
if (!rgb || rgb === 'transparent') return '#000000';
|
|
273
272
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
273
|
+
const toHex = (v) =>
|
|
274
|
+
Math.max(0, Math.min(255, Math.round(v)))
|
|
275
|
+
.toString(16)
|
|
276
|
+
.padStart(2, '0');
|
|
277
|
+
|
|
278
|
+
const srgb = rgb.match(
|
|
279
|
+
/color\(srgb\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)(?:\s*\/\s*([\d.]+))?\)/
|
|
280
|
+
);
|
|
281
|
+
if (srgb) {
|
|
282
|
+
const hex =
|
|
283
|
+
'#' +
|
|
284
|
+
toHex(srgb[1] * 255) +
|
|
285
|
+
toHex(srgb[2] * 255) +
|
|
286
|
+
toHex(srgb[3] * 255);
|
|
287
|
+
const alpha = srgb[4] === undefined ? 1 : parseFloat(srgb[4]);
|
|
288
|
+
return (alpha < 1 ? `${hex} / ${alpha}` : hex).toUpperCase();
|
|
279
289
|
}
|
|
280
290
|
|
|
291
|
+
const rgbArray = rgb.match(
|
|
292
|
+
/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/
|
|
293
|
+
);
|
|
281
294
|
if (!rgbArray) return rgb;
|
|
282
295
|
|
|
283
|
-
const
|
|
284
|
-
|
|
285
|
-
const
|
|
286
|
-
|
|
287
|
-
return `#${r}${g}${b}`.toUpperCase();
|
|
296
|
+
const hex =
|
|
297
|
+
'#' + toHex(rgbArray[1]) + toHex(rgbArray[2]) + toHex(rgbArray[3]);
|
|
298
|
+
const alpha = rgbArray[4] === undefined ? 1 : parseFloat(rgbArray[4]);
|
|
299
|
+
return (alpha < 1 ? `${hex} / ${alpha}` : hex).toUpperCase();
|
|
288
300
|
}
|
|
289
301
|
|
|
290
302
|
// ===== Accordions =====
|
|
@@ -306,6 +318,11 @@
|
|
|
306
318
|
|
|
307
319
|
if (!menuBtn || !navbar) return;
|
|
308
320
|
|
|
321
|
+
function closeMenu() {
|
|
322
|
+
menuBtn.classList.remove('open');
|
|
323
|
+
navbar.classList.remove('open');
|
|
324
|
+
}
|
|
325
|
+
|
|
309
326
|
function toggleMenu(e) {
|
|
310
327
|
e.preventDefault();
|
|
311
328
|
e.stopPropagation();
|
|
@@ -316,6 +333,17 @@
|
|
|
316
333
|
// Add multiple event listeners for better iOS compatibility
|
|
317
334
|
menuBtn.addEventListener('click', toggleMenu);
|
|
318
335
|
menuBtn.addEventListener('touchstart', toggleMenu, { passive: false });
|
|
336
|
+
|
|
337
|
+
// The scrim is a body pseudo-element, so its taps land on the document
|
|
338
|
+
document.addEventListener('click', function (e) {
|
|
339
|
+
if (!navbar.classList.contains('open')) return;
|
|
340
|
+
if (navbar.contains(e.target) || menuBtn.contains(e.target)) return;
|
|
341
|
+
closeMenu();
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
document.addEventListener('keydown', function (e) {
|
|
345
|
+
if (e.key === 'Escape') closeMenu();
|
|
346
|
+
});
|
|
319
347
|
}
|
|
320
348
|
|
|
321
349
|
// ===== Progress Bars =====
|
|
@@ -40,19 +40,17 @@
|
|
|
40
40
|
</p>
|
|
41
41
|
<pre class="mw-code-block"><code>/* Your custom-styles.css */
|
|
42
42
|
:root {
|
|
43
|
-
/*
|
|
44
|
-
|
|
43
|
+
/* Root colors — hover tones, translucent backgrounds and borders
|
|
44
|
+
are derived from them at runtime via color-mix() */
|
|
45
|
+
--mw-primary-color: #e94560;
|
|
45
46
|
--mw-secondary-color: #f39c12;
|
|
46
|
-
|
|
47
|
-
/*
|
|
48
|
-
--mw-dark-page-background: #1a1a2e;
|
|
49
|
-
--mw-light-
|
|
50
|
-
|
|
51
|
-
/*
|
|
52
|
-
--mw-
|
|
53
|
-
|
|
54
|
-
/* Override font */
|
|
55
|
-
--mw-font-family-base: 'Your Custom Font', sans-serif;
|
|
47
|
+
|
|
48
|
+
/* Theme colors */
|
|
49
|
+
--mw-dark-page-background: #1a1a2e;
|
|
50
|
+
--mw-light-page-background: #f0f0f5;
|
|
51
|
+
|
|
52
|
+
/* Font */
|
|
53
|
+
--mw-font-family-base: 'Your Custom Font', sans-serif;
|
|
56
54
|
}</code></pre>
|
|
57
55
|
<p>This method is flexible and doesn't require a Sass build process.</p>
|
|
58
56
|
|
|
@@ -61,24 +59,21 @@
|
|
|
61
59
|
</h5>
|
|
62
60
|
<p>
|
|
63
61
|
If you integrate MaverickWave's SCSS source files into your project,
|
|
64
|
-
|
|
65
|
-
<
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
framework) to automatically use your custom base colors.
|
|
62
|
+
pass your overrides through <code>@use ... with (...)</code>. A plain
|
|
63
|
+
assignment before the <code>@use</code> has no effect — the root
|
|
64
|
+
colors are declared with <code>!default</code>, which only the
|
|
65
|
+
configuration reaches.
|
|
69
66
|
</p>
|
|
70
|
-
<pre class="mw-code-block"><code>// Your
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
// Import MaverickWave
|
|
78
|
-
@import 'path/to/maverick-wave/scss/maverick-wave';</code></pre>
|
|
67
|
+
<pre class="mw-code-block"><code>// Your styles.scss
|
|
68
|
+
|
|
69
|
+
@use 'path/to/maverick-wave/src/scss/main' with (
|
|
70
|
+
$primary-color: #e94560,
|
|
71
|
+
$mw-theme-mode: 'dark' // 'switchable' | 'dark' | 'light'
|
|
72
|
+
);</code></pre>
|
|
79
73
|
<p>
|
|
80
74
|
This method requires you to have a Sass compiler set up in your
|
|
81
|
-
project.
|
|
75
|
+
project. Single components can be imported instead of
|
|
76
|
+
<code>main</code> — see the "Get Started" section.
|
|
82
77
|
</p>
|
|
83
78
|
<p class="mw-mt-4">
|
|
84
79
|
<button
|
|
@@ -118,3 +118,29 @@
|
|
|
118
118
|
</button>
|
|
119
119
|
</div>
|
|
120
120
|
</div>
|
|
121
|
+
|
|
122
|
+
<h4 class="mw-mb-2 mw-mt-8">Toast Stack</h4>
|
|
123
|
+
<p class="mw-text-muted mw-mb-3">
|
|
124
|
+
Alerts become toasts by putting them in a fixed, stacked container. Positions:
|
|
125
|
+
<code>mw-toast-stack-top-right</code> (default),
|
|
126
|
+
<code>mw-toast-stack-top-center</code>,
|
|
127
|
+
<code>mw-toast-stack-bottom-right</code>. Auto-dismiss stays the application's
|
|
128
|
+
job.
|
|
129
|
+
</p>
|
|
130
|
+
|
|
131
|
+
<div class="mw-card mw-card-simple">
|
|
132
|
+
<pre
|
|
133
|
+
class="mw-code-block"
|
|
134
|
+
><code><div class="mw-toast-stack mw-toast-stack-top-right">
|
|
135
|
+
<div class="mw-alert mw-alert-success">
|
|
136
|
+
<div class="mw-alert-icon"><i class="fas fa-check-circle"></i></div>
|
|
137
|
+
<div class="mw-alert-content">Entry saved.</div>
|
|
138
|
+
</div>
|
|
139
|
+
</div></code></pre>
|
|
140
|
+
<p class="mw-text-muted mw-text-sm">
|
|
141
|
+
The container is <code>position: fixed</code>, so it cannot be shown inline
|
|
142
|
+
here. Its width is capped at <code>min(380px, calc(100vw - 2rem))</code>, it
|
|
143
|
+
lets clicks pass through everywhere except on a toast, and the entry
|
|
144
|
+
animation respects <code>prefers-reduced-motion</code>.
|
|
145
|
+
</p>
|
|
146
|
+
</div>
|
|
@@ -64,6 +64,28 @@
|
|
|
64
64
|
</div>
|
|
65
65
|
</div>
|
|
66
66
|
|
|
67
|
+
<h4 class="mw-mb-2 mw-mt-4">Avatar Initials</h4>
|
|
68
|
+
<p class="mw-text-muted mw-text-sm">
|
|
69
|
+
For users without a picture. The color variants tint the surface here
|
|
70
|
+
instead of the border.
|
|
71
|
+
</p>
|
|
72
|
+
<div>
|
|
73
|
+
<div class="mw-avatar mw-avatar-initials mw-avatar-xs">MW</div>
|
|
74
|
+
<div class="mw-avatar mw-avatar-initials mw-avatar-sm">AB</div>
|
|
75
|
+
<div class="mw-avatar mw-avatar-initials">CD</div>
|
|
76
|
+
<div class="mw-avatar mw-avatar-initials mw-avatar-secondary">EF</div>
|
|
77
|
+
</div>
|
|
78
|
+
<div>
|
|
79
|
+
<div class="mw-avatar mw-avatar-initials mw-avatar-success">GH</div>
|
|
80
|
+
<div class="mw-avatar mw-avatar-initials mw-avatar-warning">IJ</div>
|
|
81
|
+
<div class="mw-avatar mw-avatar-initials mw-avatar-danger">KL</div>
|
|
82
|
+
<div
|
|
83
|
+
class="mw-avatar mw-avatar-initials mw-avatar-info mw-avatar-square"
|
|
84
|
+
>
|
|
85
|
+
MN
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
|
|
67
89
|
<h4 class="mw-mb-2 mw-mt-4">Avatar Group</h4>
|
|
68
90
|
<div class="mw-avatar-group mw-mt-3 mw-mb-5">
|
|
69
91
|
<div class="mw-avatar mw-avatar-sm">
|
|
@@ -11,6 +11,12 @@
|
|
|
11
11
|
<button type="button" class="mw-btn mw-btn-secondary">
|
|
12
12
|
Secondary Button
|
|
13
13
|
</button>
|
|
14
|
+
<button type="button" class="mw-btn mw-btn-danger">
|
|
15
|
+
Danger Button
|
|
16
|
+
</button>
|
|
17
|
+
<button type="button" class="mw-btn mw-btn-success">
|
|
18
|
+
Success Button
|
|
19
|
+
</button>
|
|
14
20
|
<button type="button" class="mw-btn mw-btn-outline">
|
|
15
21
|
Outline Button
|
|
16
22
|
</button>
|
|
@@ -46,37 +52,27 @@
|
|
|
46
52
|
<h3 class="mw-mb-4">Buttons with Icons</h3>
|
|
47
53
|
<div class="mw-card mw-card-simple">
|
|
48
54
|
<div class="mw-d-flex mw-flex-wrap mw-items-center mw-gap-4">
|
|
49
|
-
<button type="button" class="mw-btn mw-btn-primary
|
|
55
|
+
<button type="button" class="mw-btn mw-btn-primary">
|
|
50
56
|
<i class="fas fa-save"></i>
|
|
51
57
|
Save Changes
|
|
52
58
|
</button>
|
|
53
59
|
|
|
54
|
-
<button type="button" class="mw-btn mw-btn-secondary
|
|
60
|
+
<button type="button" class="mw-btn mw-btn-secondary">
|
|
55
61
|
<i class="fas fa-plus"></i>
|
|
56
62
|
Add Item
|
|
57
63
|
</button>
|
|
58
64
|
|
|
59
|
-
<button
|
|
60
|
-
type="button"
|
|
61
|
-
href="#"
|
|
62
|
-
class="mw-btn mw-btn-outline mw-btn-icon"
|
|
63
|
-
>
|
|
65
|
+
<button type="button" href="#" class="mw-btn mw-btn-outline">
|
|
64
66
|
<i class="fas fa-arrow-left"></i>
|
|
65
67
|
Go Back
|
|
66
68
|
</button>
|
|
67
69
|
|
|
68
|
-
<button
|
|
69
|
-
type="button"
|
|
70
|
-
class="mw-btn mw-btn-primary mw-btn-sm mw-btn-icon"
|
|
71
|
-
>
|
|
70
|
+
<button type="button" class="mw-btn mw-btn-primary mw-btn-sm">
|
|
72
71
|
<i class="fas fa-check"></i>
|
|
73
72
|
OK
|
|
74
73
|
</button>
|
|
75
74
|
|
|
76
|
-
<button
|
|
77
|
-
type="button"
|
|
78
|
-
class="mw-btn mw-btn-outline mw-btn-lg mw-btn-icon"
|
|
79
|
-
>
|
|
75
|
+
<button type="button" class="mw-btn mw-btn-outline mw-btn-lg">
|
|
80
76
|
<i class="fas fa-upload"></i>
|
|
81
77
|
Upload File
|
|
82
78
|
</button>
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
<h5 class="mw-card-stack-title">Frontend</h5>
|
|
72
72
|
</div>
|
|
73
73
|
<div class="mw-card-stack-body">
|
|
74
|
-
<div class="mw-tags
|
|
74
|
+
<div class="mw-tags">
|
|
75
75
|
<span class="mw-tags-item">React</span>
|
|
76
76
|
<span class="mw-tags-item">TypeScript</span>
|
|
77
77
|
<span class="mw-tags-item">Next.js</span>
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
<h5 class="mw-card-stack-title">Backend</h5>
|
|
92
92
|
</div>
|
|
93
93
|
<div class="mw-card-stack-body">
|
|
94
|
-
<div class="mw-tags
|
|
94
|
+
<div class="mw-tags">
|
|
95
95
|
<span class="mw-tags-item">Node.js</span>
|
|
96
96
|
<span class="mw-tags-item">Express</span>
|
|
97
97
|
<span class="mw-tags-item">NestJS</span>
|
|
@@ -111,7 +111,7 @@
|
|
|
111
111
|
<h5 class="mw-card-stack-title">Data Storage</h5>
|
|
112
112
|
</div>
|
|
113
113
|
<div class="mw-card-stack-body">
|
|
114
|
-
<div class="mw-tags
|
|
114
|
+
<div class="mw-tags">
|
|
115
115
|
<span class="mw-tags-item">MongoDB</span>
|
|
116
116
|
<span class="mw-tags-item">PostgreSQL</span>
|
|
117
117
|
<span class="mw-tags-item">Redis</span>
|
|
@@ -131,7 +131,7 @@
|
|
|
131
131
|
<h5 class="mw-card-stack-title">DevOps & Cloud</h5>
|
|
132
132
|
</div>
|
|
133
133
|
<div class="mw-card-stack-body">
|
|
134
|
-
<div class="mw-tags
|
|
134
|
+
<div class="mw-tags">
|
|
135
135
|
<span class="mw-tags-item">Docker</span>
|
|
136
136
|
<span class="mw-tags-item">GitHub Actions</span>
|
|
137
137
|
<span class="mw-tags-item">AWS</span>
|
|
@@ -280,10 +280,10 @@
|
|
|
280
280
|
<p class="mw-card-text">
|
|
281
281
|
Tags can be used to categorize content or show related topics.
|
|
282
282
|
</p>
|
|
283
|
-
<div class="mw-
|
|
284
|
-
<span class="mw-
|
|
285
|
-
<span class="mw-
|
|
286
|
-
<span class="mw-
|
|
283
|
+
<div class="mw-d-flex mw-flex-wrap mw-gap-2">
|
|
284
|
+
<span class="mw-tag mw-tag-primary">Primary</span>
|
|
285
|
+
<span class="mw-tag mw-tag-success">Success</span>
|
|
286
|
+
<span class="mw-tag mw-tag-danger">Danger</span>
|
|
287
287
|
</div>
|
|
288
288
|
<div class="mw-card-footer">
|
|
289
289
|
<button type="button" class="mw-btn mw-btn-link">Learn More</button>
|
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- the hex code string is getting updated via javascript! -->
|
|
4
4
|
|
|
5
|
+
<p class="mw-text-muted mw-mb-6">
|
|
6
|
+
These twelve are the only colors you ever set. Everything else — hover
|
|
7
|
+
tones, translucent backgrounds, borders, muted text — is derived from
|
|
8
|
+
them at runtime with <code>color-mix()</code>, so overriding a root token
|
|
9
|
+
cascades to all of its variants.
|
|
10
|
+
</p>
|
|
11
|
+
|
|
5
12
|
<div class="mw-grid-auto-sm">
|
|
6
13
|
<div class="mw-card mw-card-simple color-card">
|
|
7
14
|
<div class="mw-text-center">
|
|
@@ -29,9 +36,9 @@
|
|
|
29
36
|
<div class="mw-text-center">
|
|
30
37
|
<div
|
|
31
38
|
class="color-swatch"
|
|
32
|
-
style="background: var(--mw-
|
|
39
|
+
style="background: var(--mw-success-color)"
|
|
33
40
|
></div>
|
|
34
|
-
<p>
|
|
41
|
+
<p>Success</p>
|
|
35
42
|
<p class="mw-text-muted">#000000</p>
|
|
36
43
|
</div>
|
|
37
44
|
</div>
|
|
@@ -40,33 +47,36 @@
|
|
|
40
47
|
<div class="mw-text-center">
|
|
41
48
|
<div
|
|
42
49
|
class="color-swatch"
|
|
43
|
-
style="background: var(--mw-
|
|
50
|
+
style="background: var(--mw-warning-color)"
|
|
44
51
|
></div>
|
|
45
|
-
<p>
|
|
52
|
+
<p>Warning</p>
|
|
46
53
|
<p class="mw-text-muted">#000000</p>
|
|
47
54
|
</div>
|
|
48
55
|
</div>
|
|
49
56
|
|
|
50
57
|
<div class="mw-card mw-card-simple color-card">
|
|
51
58
|
<div class="mw-text-center">
|
|
52
|
-
<div
|
|
53
|
-
|
|
59
|
+
<div
|
|
60
|
+
class="color-swatch"
|
|
61
|
+
style="background: var(--mw-danger-color)"
|
|
62
|
+
></div>
|
|
63
|
+
<p>Danger</p>
|
|
54
64
|
<p class="mw-text-muted">#000000</p>
|
|
55
65
|
</div>
|
|
56
66
|
</div>
|
|
57
67
|
|
|
58
68
|
<div class="mw-card mw-card-simple color-card">
|
|
59
69
|
<div class="mw-text-center">
|
|
60
|
-
<div class="color-swatch" style="background: var(--mw-
|
|
61
|
-
<p>
|
|
70
|
+
<div class="color-swatch" style="background: var(--mw-info-color)"></div>
|
|
71
|
+
<p>Info</p>
|
|
62
72
|
<p class="mw-text-muted">#000000</p>
|
|
63
73
|
</div>
|
|
64
74
|
</div>
|
|
65
75
|
|
|
66
76
|
<div class="mw-card mw-card-simple color-card">
|
|
67
77
|
<div class="mw-text-center">
|
|
68
|
-
<div class="color-swatch" style="background: var(--mw-
|
|
69
|
-
<p>
|
|
78
|
+
<div class="color-swatch" style="background: var(--mw-gray-color)"></div>
|
|
79
|
+
<p>Gray</p>
|
|
70
80
|
<p class="mw-text-muted">#000000</p>
|
|
71
81
|
</div>
|
|
72
82
|
</div>
|
|
@@ -75,9 +85,9 @@
|
|
|
75
85
|
<div class="mw-text-center">
|
|
76
86
|
<div
|
|
77
87
|
class="color-swatch"
|
|
78
|
-
style="background: var(--mw-text-
|
|
88
|
+
style="background: var(--mw-accent-text-color)"
|
|
79
89
|
></div>
|
|
80
|
-
<p>Text
|
|
90
|
+
<p>Accent Text</p>
|
|
81
91
|
<p class="mw-text-muted">#000000</p>
|
|
82
92
|
</div>
|
|
83
93
|
</div>
|
|
@@ -86,9 +96,9 @@
|
|
|
86
96
|
<div class="mw-text-center">
|
|
87
97
|
<div
|
|
88
98
|
class="color-swatch"
|
|
89
|
-
style="background: var(--mw-
|
|
99
|
+
style="background: var(--mw-dark-page-background)"
|
|
90
100
|
></div>
|
|
91
|
-
<p>
|
|
101
|
+
<p>Dark Page</p>
|
|
92
102
|
<p class="mw-text-muted">#000000</p>
|
|
93
103
|
</div>
|
|
94
104
|
</div>
|
|
@@ -97,9 +107,9 @@
|
|
|
97
107
|
<div class="mw-text-center">
|
|
98
108
|
<div
|
|
99
109
|
class="color-swatch"
|
|
100
|
-
style="background: var(--mw-
|
|
110
|
+
style="background: var(--mw-dark-text-color)"
|
|
101
111
|
></div>
|
|
102
|
-
<p>
|
|
112
|
+
<p>Dark Text</p>
|
|
103
113
|
<p class="mw-text-muted">#000000</p>
|
|
104
114
|
</div>
|
|
105
115
|
</div>
|
|
@@ -108,17 +118,20 @@
|
|
|
108
118
|
<div class="mw-text-center">
|
|
109
119
|
<div
|
|
110
120
|
class="color-swatch"
|
|
111
|
-
style="background: var(--mw-
|
|
121
|
+
style="background: var(--mw-light-page-background)"
|
|
112
122
|
></div>
|
|
113
|
-
<p>
|
|
123
|
+
<p>Light Page</p>
|
|
114
124
|
<p class="mw-text-muted">#000000</p>
|
|
115
125
|
</div>
|
|
116
126
|
</div>
|
|
117
127
|
|
|
118
128
|
<div class="mw-card mw-card-simple color-card">
|
|
119
129
|
<div class="mw-text-center">
|
|
120
|
-
<div
|
|
121
|
-
|
|
130
|
+
<div
|
|
131
|
+
class="color-swatch"
|
|
132
|
+
style="background: var(--mw-light-text-color)"
|
|
133
|
+
></div>
|
|
134
|
+
<p>Light Text</p>
|
|
122
135
|
<p class="mw-text-muted">#000000</p>
|
|
123
136
|
</div>
|
|
124
137
|
</div>
|