feat(components): add offcanvas component

This commit is contained in:
Alexander Navarro 2024-12-26 19:49:08 -03:00
parent e0ed5a5ddd
commit c47a2eff89
14 changed files with 233 additions and 129 deletions

View file

@ -8,7 +8,8 @@
"exports": { "exports": {
".": "./src/index.ts", ".": "./src/index.ts",
"./navbar/*": "./src/navbar/*", "./navbar/*": "./src/navbar/*",
"./accordion/*": "./src/accordion/*" "./accordion/*": "./src/accordion/*",
"./offcanvas/*": "./src/offcanvas/*"
}, },
"devDependencies": { "devDependencies": {
"@types/bun": "latest", "@types/bun": "latest",

View file

@ -1,59 +0,0 @@
.off-canvas {
.off-canvas-content {
overflow: hidden;
position: fixed;
height: 100vh;
z-index: 5;
background-color: var(--prj-bg);
top: 0;
right: 0;
left: 100%;
padding: var(--prj-spacing-3);
transition: left 0.4s ease-in-out;
}
&.active .off-canvas-content {
left: 50%;
}
.off-canvas-backdrop {
position: fixed;
height: 100vh;
z-index: 4;
background-color: rgba(0, 0, 0);
opacity: 0;
top: 0;
right: 0;
left: 100%;
padding: var(--prj-spacing-3);
// Delay the left transition on remove so it's desn't appear to be sliding or to be not working
transition:
opacity 0.8s ease,
left 0s linear 1s;
}
&.active .off-canvas-backdrop {
left: 0%;
opacity: 40%;
transition:
opacity 0.8s ease,
left 0s linear;
}
}
button.off-canvas-toggle {
width: 40px;
height: 40px;
padding: 0;
border: none;
background: none;
cursor: pointer;
}

View file

@ -1 +1,34 @@
<h1>Hello World!</h1> {% macro navbar() %}
<nav class="msp-navbar msp-navbar-desktop msp-d-none msp-d-lg-block msp-container">
<ul class="msp-list-unstyle msp-hstack">
{% for i in range(end=3) %}{% endfor %}
</ul>
</nav>
{% endmacro navbar %}
{% macro navbar_item(href, label) %}
<li class="msp-nav-item">
<a class="msp-nav-link active" href="{{ href }}">{{ label }}</a>
</li>
{% endmacro navbar_item %}
<div class="msp-text-end msp-d-lg-none">
<OffCanvasBtn />
<OffCanvas>
<nav class="msp-navbar msp-navbar-mobile">
<ul class="msp-list-unstyle msp-text-start">
{
links.map((link) => (
<li class="msp-nav-item msp-mb-3">
<a class="msp-nav-link" href={link.href}>{link.text}</a>
</li>
))
}
<li class="msp-nav-item mb-3">
<LangSelector />
</li>
</ul>
</nav>
</OffCanvas>
</div>

View file

@ -1,8 +1,43 @@
nav { nav.msp-navbar {
width: 100%; width: 100%;
ul {
padding: 0;
li {
margin-bottom: 0;
height: 100%;
}
}
li > a {
padding: 0.25rem 0.5rem;
}
a {
--boder-color: transparent;
border: 1px solid transparent;
border-radius: 4px;
text-decoration: none;
transition:
background-color 200ms,
color 200ms;
}
a.active {
border: 1px solid var(--msp-color-bg-accent);
}
a:hover {
--border-color: var(--msp-color-bg-accent);
background-color: var(--msp-color-bg-accent);
color: var(--msp-color-text-accent);
border: 1px solid var(--border-color);
}
} }
.navbar-desktop ul { .msp-navbar-desktop ul {
width: fit-content; width: fit-content;
margin-left: auto; margin-left: auto;
@ -10,33 +45,3 @@ nav {
margin-bottom: 0; margin-bottom: 0;
} }
} }
ul {
padding: 0;
}
li > a {
padding: 0.25rem 0.5rem;
}
a {
--boder-color: transparent;
border: 1px solid transparent;
border-radius: 4px;
text-decoration: none;
transition:
background-color 200ms,
color 200ms;
}
a.active {
border: 1px solid var(--prj-accent-bg);
}
a:hover {
--border-color: var(--prj-accent-bg);
background-color: var(--prj-accent-bg);
color: var(--prj-accent-text);
border: 1px solid var(--border-color);
}

View file

@ -0,0 +1,21 @@
import { qs, qsa } from "../utils";
window.onload = () => {
qsa(".msp-offcanvas-toggle").forEach((item) => {
item.addEventListener("click", () => {
const target = item.dataset.mspTarget;
if (!target) {
throw new Error("No target provided");
}
const targetElement = qs(target);
if (!targetElement) {
throw new Error("No target found");
}
targetElement.classList.toggle("show");
});
});
};

View file

@ -0,0 +1,66 @@
.msp-offcanvas {
--msp-offcanvas-anim-duration: var(--msp-anim-duration-md);
--msp-offcanvas-anim-curve-in: cubic-bezier(0.22, 0.61, 0.36, 1);
--msp-offcanvas-anim-curve-out: cubic-bezier(0.55, 0.06, 0.68, 0.19);
&-content {
overflow: hidden;
position: fixed;
height: 100vh;
z-index: 5;
background-color: var(--msp-color-bg);
top: 0;
left: -100%;
padding: var(--msp-spacing-3);
transition: left var(--msp-offcanvas-anim-duration)
var(--msp-offcanvas-anim-curve-out);
&-body,
&-header,
&-footer {
position: relative;
z-index: 5;
}
}
&.show {
.msp-offcanvas-backdrop {
opacity: 40%;
left: 0;
transition:
opacity var(--msp-offcanvas-anim-duration)
var(--msp-offcanvas-anim-curve-in),
left 0s linear;
}
.msp-offcanvas-content {
left: 0;
transition: left var(--msp-offcanvas-anim-duration)
var(--msp-offcanvas-anim-curve-in);
}
}
.msp-offcanvas-backdrop {
position: fixed;
height: 100vh;
width: 100vw;
z-index: 4;
background-color: rgba(0, 0, 0);
opacity: 0;
top: 0;
left: -100%;
// Delay the width transition on remove so it's desn't appear to be sliding or to be not working
transition:
opacity var(--msp-offcanvas-anim-duration)
var(--msp-offcanvas-anim-curve-out),
left 0s linear var(--msp-offcanvas-anim-duration);
}
}

View file

@ -91,6 +91,12 @@ $msp-colors: (
"--msp-color-transparent": transparent, "--msp-color-transparent": transparent,
); );
$anim: (
"--msp-anim-duration-sm": 0.4s,
"--msp-anim-duration-md": 0.8s,
"--msp-anim-duration-lg": 1s,
);
// Native CSS Variables to allow overridings and usage in external stylesheets // Native CSS Variables to allow overridings and usage in external stylesheets
:root { :root {
@each $variable, $value in $msp-colors { @each $variable, $value in $msp-colors {
@ -101,6 +107,10 @@ $msp-colors: (
#{$variable}: #{$value}; #{$variable}: #{$value};
} }
@each $variable, $value in $anim {
#{$variable}: #{$value};
}
// Borders // Borders
--msp-border-width: 1px; --msp-border-width: 1px;
--msp-border-color: var(--msp-color-text-transparent); --msp-border-color: var(--msp-color-text-transparent);

View file

@ -123,10 +123,18 @@
align-items: center; align-items: center;
} }
.msp-justify-content-start {
justify-content: start !important;
}
.msp-justify-content-center { .msp-justify-content-center {
justify-content: center !important; justify-content: center !important;
} }
.msp-justify-content-end {
justify-content: end !important;
}
.msp-justify-content-between { .msp-justify-content-between {
justify-content: space-between !important; justify-content: space-between !important;
} }

View file

@ -1,2 +1,3 @@
import "@mini-strap/components/accordion/index.ts"; import "@mini-strap/components/accordion/index.ts";
import "@mini-strap/components/offcanvas/index.ts";
console.log("hello world!"); console.log("hello world!");

View file

@ -0,0 +1 @@
/home/aleidk/Repos/Projects/mini-strap/packages/core/src/style.scss

View file

@ -1,6 +1,7 @@
@use "@mini-strap/core"; @use "@mini-strap/core";
@use "@mini-strap/components/navbar/navbar.scss"; @use "@mini-strap/components/navbar/navbar.scss";
@use "@mini-strap/components/accordion/accordion.scss"; @use "@mini-strap/components/accordion/accordion.scss";
@use "@mini-strap/components/offcanvas/style.scss";
html { html {
// background-color: red; // background-color: red;

View file

@ -1,25 +1,26 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="description" content="Astro description" /> <meta name="description" content="Astro description" />
<meta name="viewport" content="width=device-width" /> <meta name="viewport" content="width=device-width" />
<title>alecodes.page</title> <title>alecodes.page</title>
<ViewTransitions /> <ViewTransitions />
{% block scripts %}<script src="/js/index.js"></script>{% endblock %} {% block scripts %}
<link rel="stylesheet" href="/css/style.css" /> <script src="/js/index.js"></script>{% endblock %}
<link rel="stylesheet" href="/css/style.css" />
</head> </head>
<body transition:animate="fade"> <body transition:animate="fade">
<header class="msp-position-sticky msp-py-1 msp-py-lg-3"> <header class="msp-py-1 msp-py-lg-3">
{% include "partials/header.html" %} {% include "partials/header.html" %}
</header> </header>
<main> <main>
{% block content %}{% endblock %} {% block content %}{% endblock %}
</main> </main>
</body> </body>
</html> </html>

View file

@ -1,20 +1,35 @@
<ul class="msp-list-unstyle msp-accordion"> <aside id="main-offcanvas" class="msp-offcanvas">
<li> <div class="msp-offcanvas-backdrop msp-offcanvas-toggle"
<a href="/">Overview</a> data-msp-target="#main-offcanvas"></div>
</li>
{% for item in get_taxonomy(kind="section") | get(key="items") %} <div class="msp-offcanvas-content">
<li class="msp-accordion-item"> <div class="msp-offcanvas-body">
<a class="msp-accordion-header" href="{{ get_url(path="@/" ~ item.slug ~ "/_index.md") }}">{{ item.name | title }}</a> <ul class="msp-list-unstyle msp-accordion">
<div class="msp-accordion-collapse"> <li>
<ul class="msp-list-unstyle msp-accordion-content"> <a href="/">Overview</a>
{% for page in item.pages %} </li>
<li class="">
<a href="{{ page.permalink }}">{{ page.title | default(value=page.slug) | title }}</a> {% for item in get_taxonomy(kind="section") | get(key="items") %}
</li> <li class="msp-accordion-item">
{% endfor %} <a class="msp-accordion-header" href="{{ get_url(path="@/" ~ item.slug ~ "/_index.md") }}">{{ item.name |
</ul> title
</div> }}</a>
</li> <div class="msp-accordion-collapse">
{% endfor %} <ul class="msp-list-unstyle msp-accordion-content">
</ul> {% for page in item.pages %}
<li class="">
<a href="{{ page.permalink }}">{{ page.title | default(value=page.slug) | title }}</a>
</li>
{% endfor %}
</ul>
</div>
</li>
{% endfor %}
</ul>
</div>
</div>
</aside>
<nav class="msp-d-flex msp-justify-content-end">
<button class="msp-offcanvas-toggle" data-msp-target="#main-offcanvas">Toggle</button>
</nav>