diff --git a/packages/components/package.json b/packages/components/package.json index 9bc0fe8..c30bc4a 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -7,7 +7,8 @@ }, "exports": { ".": "./src/index.ts", - "./navbar/*": "./src/navbar/*" + "./navbar/*": "./src/navbar/*", + "./accordion/*": "./src/accordion/*" }, "devDependencies": { "@types/bun": "latest", diff --git a/packages/components/src/accordion/accordion.scss b/packages/components/src/accordion/accordion.scss new file mode 100644 index 0000000..39555c5 --- /dev/null +++ b/packages/components/src/accordion/accordion.scss @@ -0,0 +1,41 @@ +.msp-accordion { + // background-color: red; + + &-item.msp-accordion-show { + .msp-accordion-header::after { + transform: rotate(180deg); + } + } + &-header { + cursor: pointer; + position: relative; + + &::after { + display: inline-block; + position: absolute; + top: 50%; + right: 0; + + transform: rotate(0deg); + translate: 110% -50%; + + content: ""; + width: 1em; + height: 1em; + // TODO: change SVG of the arrow + background: url('data:image/svg+xml;utf8,') + no-repeat center center; + background-size: contain; + + transition: transform 0.5s ease; + } + } + + &-collapse { + overflow: hidden; + height: 0; + display: none; + + transition: height 0.5s ease; + } +} diff --git a/packages/components/src/accordion/index.ts b/packages/components/src/accordion/index.ts new file mode 100644 index 0000000..9a2775c --- /dev/null +++ b/packages/components/src/accordion/index.ts @@ -0,0 +1,53 @@ +import { qs, qsa } from "../utils"; + +enum AccordionState { + Open = 1, + Closed = 2, +} + +function waitAndHideCollapse(e: TransitionEvent) { + if (!e.target) return; + + const el = e.target as HTMLElement; + el.style.display = "none"; + el.removeEventListener("transitionend", waitAndHideCollapse); +} + +function toggleAccordion(item: HTMLElement, state: AccordionState) { + const collapse = qs(".msp-accordion-collapse", item); + + if (!collapse) throw new Error("Collapse element not found"); + + if (state === AccordionState.Closed) { + collapse.style.height = "0px"; + collapse + .closest(".msp-accordion-item") + ?.classList.remove("msp-accordion-show"); + + collapse.addEventListener("transitionend", waitAndHideCollapse); + } else if (state === AccordionState.Open) { + collapse.style.display = "block"; + + const height = qs(".msp-accordion-content", collapse)?.offsetHeight; + if (height == null) throw new Error("Content element not found"); + + collapse.style.height = `${height}px`; + collapse + .closest(".msp-accordion-item") + ?.classList.add("msp-accordion-show"); + } +} + +window.onload = () => { + qsa(".msp-accordion-item").forEach((item) => { + qs(".msp-accordion-header", item)?.addEventListener("click", (e) => { + e.preventDefault(); + toggleAccordion( + item, + item.classList.contains("msp-accordion-show") + ? AccordionState.Closed + : AccordionState.Open, + ); + }); + }); +}; diff --git a/packages/components/src/utils.ts b/packages/components/src/utils.ts new file mode 100644 index 0000000..0df8cd7 --- /dev/null +++ b/packages/components/src/utils.ts @@ -0,0 +1,13 @@ +export const qs = ( + query: string, + el: Element | Document = document, +): HTMLElement | null => { + return el.querySelector(query); +}; + +export const qsa = ( + query: string, + el: Element | Document = document, +): NodeListOf => { + return el.querySelectorAll(query); +}; diff --git a/packages/website/_scripts/build.ts b/packages/website/_scripts/build.ts index 54b8e4f..a49e87b 100644 --- a/packages/website/_scripts/build.ts +++ b/packages/website/_scripts/build.ts @@ -9,6 +9,11 @@ import { HTMLComponents } from "@mini-strap/components"; const { values } = parseArgs({ args: Bun.argv, options: { + production: { + type: "boolean", + short: "p", + default: false, + }, filter: { type: "string", short: "f", @@ -64,7 +69,7 @@ if (["all", "sass"].includes(filter)) { outdir: `${outdir}/css`, naming: "[name].css", plugins: [sassPlugin], - minify: true, + minify: values.production, // On by default in Bun v1.2+ html: true, @@ -77,8 +82,8 @@ if (["all", "js", "ts"].includes(filter)) { entrypoints: ["./js/index.ts"], outdir: `${outdir}/js`, target: "browser", - splitting: true, - minify: true, + splitting: values.production, + minify: values.production, }); } diff --git a/packages/website/content/components/accordion.md b/packages/website/content/components/accordion.md index 0185b94..51987ec 100644 --- a/packages/website/content/components/accordion.md +++ b/packages/website/content/components/accordion.md @@ -4,3 +4,28 @@ section = ["Components"] +++ # accordion.md + +Example: + +```html + +``` diff --git a/packages/website/js/index.ts b/packages/website/js/index.ts index a50e789..cfe5636 100644 --- a/packages/website/js/index.ts +++ b/packages/website/js/index.ts @@ -1 +1,2 @@ +import "@mini-strap/components/accordion/index.ts"; console.log("hello world!"); diff --git a/packages/website/sass/style.scss b/packages/website/sass/style.scss index 4643c8a..94868e5 100644 --- a/packages/website/sass/style.scss +++ b/packages/website/sass/style.scss @@ -1,4 +1,6 @@ @use "@mini-strap/core"; +@use "@mini-strap/components/navbar/navbar.scss"; +@use "@mini-strap/components/accordion/accordion.scss"; html { // background-color: red; diff --git a/packages/website/templates/base.html b/packages/website/templates/base.html index b3cc53d..a2e6a6e 100644 --- a/packages/website/templates/base.html +++ b/packages/website/templates/base.html @@ -8,8 +8,9 @@ alecodes.page - + {% block scripts %}{% endblock %} + diff --git a/packages/website/templates/partials/header.html b/packages/website/templates/partials/header.html index 901df72..60ca2b4 100644 --- a/packages/website/templates/partials/header.html +++ b/packages/website/templates/partials/header.html @@ -1,18 +1,20 @@ -