feat(Style): update responsive design of landing page

fix overflow issues in small screens, hide full navbar on mobile and replace for an off-canvas version
This commit is contained in:
Alexander Navarro 2024-03-13 20:05:15 -03:00
parent daa5eb27b6
commit d49fe554ee
4 changed files with 345 additions and 127 deletions

View file

@ -0,0 +1,17 @@
@use './variables' as *;
@mixin responsive {
@each $size-name, $size in $screen-sizes {
@media screen and (min-width: $size) {
@content ($size-name);
}
}
}
@mixin responsive-steps($from, $to) {
@include responsive using ($size-name) {
@for $index from $from through $to {
@content ($size-name, $index);
}
}
}

View file

@ -1,17 +1,58 @@
@use './variables' as *;
@use './mixins';
.d-none {
display: none;
}
.d-block {
display: block;
}
.d-flex {
display: flex;
}
.visually-hidden {
height: 0;
width: 0;
position: absolute;
overflow: hidden;
}
@include mixins.responsive using($screen-size) {
.d-#{$screen-size}-none {
display: none;
}
.d-#{$screen-size}-block {
display: block;
}
.d-#{$screen-size}-flex {
display: flex;
}
}
.flex-eq > * {
flex: 100%;
}
.flex-column {
flex-direction: column !important;
}
.flex-row {
flex-direction: row !important;
}
@include mixins.responsive using($screen-size) {
.flex-#{$screen-size}-column {
flex-direction: column !important;
}
.flex-#{$screen-size}-row {
flex-direction: row !important;
}
}
.hstack {
--prj-gap: var(--prj-spacing-3);
display: flex;
@ -50,15 +91,13 @@
flex-wrap: nowrap;
}
@each $name, $size in $screen-sizes {
@media screen and (min-width: $size) {
.flex-#{$name}-wrap {
flex-wrap: wrap;
}
@include mixins.responsive using($size-name) {
.flex-#{$size-name}-wrap {
flex-wrap: wrap;
}
.flex-#{$name}-nowrap {
flex-wrap: nowrap;
}
.flex-#{$size-name}-nowrap {
flex-wrap: nowrap;
}
}
@ -72,6 +111,14 @@
justify-content: center !important;
}
.justify-content-between {
justify-content: space-between !important;
}
.justify-content-around {
justify-content: space-around !important;
}
.grid {
--prj-gap: var(--prj-spacing-3);
--prj-columns: repeat(3, 1fr);
@ -81,15 +128,19 @@
gap: var(--prj-gap);
}
@mixin grid-cols($amount) {
--prj-columns: repeat(#{$amount}, minmax(var(--prj-min-col-width), 1fr));
}
@for $i from 1 through 12 {
.grid-cols-#{$i} {
--prj-columns: repeat(#{$i}, minmax(var(--prj-min-col-width), 1fr));
@include grid-cols($i);
}
}
@each $index, $variable, $value in $spacings {
.gap-#{$index} {
--prj-gap: var(#{$variable});
@include mixins.responsive-steps(1, 12) using ($size-name, $index) {
.grid-#{$size-name}-cols-#{$index} {
@include grid-cols($index);
}
}
@ -151,99 +202,82 @@
}
}
.m-auto {
margin: auto !important;
@include mixins.responsive-steps(0, 100) using ($size-name, $index) {
.w-#{$size-name}-#{$index} {
width: percentage($index / 100);
}
.h-#{$size-name}-#{$index} {
height: percentage($index / 100);
}
}
.mx-auto {
margin-left: auto !important;
margin-right: auto !important;
@mixin spacing-utils($name, $value, $screen-size: false) {
@if $screen-size {
$name: '#{$screen-size}-#{$name}';
}
.m-#{$name} {
margin: $value !important;
}
.mx-#{$name} {
margin-left: $value !important;
margin-right: $value !important;
}
.my-#{$name} {
margin-top: $value !important;
margin-bottom: $value !important;
}
.mt-#{$name} {
margin-top: $value !important;
}
.mb-#{$name} {
margin-bottom: $value !important;
}
.ml-#{$name} {
margin-left: $value !important;
}
.mr-#{$name} {
margin-right: $value !important;
}
.p-#{$name} {
padding: $value !important;
}
.px-#{$name} {
padding-left: $value !important;
padding-right: $value !important;
}
.py-#{$name} {
padding-top: $value !important;
padding-bottom: $value !important;
}
.pt-#{$name} {
padding-top: $value !important;
}
.pb-#{$name} {
padding-bottom: $value !important;
}
.pl-#{$name} {
padding-left: $value !important;
}
.pr-#{$name} {
padding-right: $value !important;
}
.gap-#{$name} {
--prj-gap: #{$value};
}
}
.my-auto {
margin-top: auto !important;
margin-bottom: auto !important;
}
.mt-auto {
margin-top: auto !important;
}
.mb-auto {
margin-bottom: auto !important;
}
.ml-auto {
margin-left: auto !important;
}
.mr-auto {
margin-right: auto !important;
}
.p-auto {
padding: auto !important;
}
.px-auto {
padding-left: auto !important;
padding-right: auto !important;
}
.py-auto {
padding-top: auto !important;
padding-bottom: auto !important;
}
.pt-auto {
padding-top: auto !important;
}
.pb-auto {
padding-bottom: auto !important;
}
.pl-auto {
padding-left: auto !important;
}
.pr-auto {
padding-right: var(--prj-spacing-5) !important;
@include spacing-utils(auto, auto);
@include mixins.responsive using($screen-size) {
@include spacing-utils(auto, auto);
}
@each $index, $variable, $value in $spacings {
.m-#{$index} {
margin: var(#{$variable}) !important;
}
.mx-#{$index} {
margin-left: var(#{$variable}) !important;
margin-right: var(#{$variable}) !important;
}
.my-#{$index} {
margin-top: var(#{$variable}) !important;
margin-bottom: var(#{$variable}) !important;
}
.mt-#{$index} {
margin-top: var(#{$variable}) !important;
}
.mb-#{$index} {
margin-bottom: var(#{$variable}) !important;
}
.ml-#{$index} {
margin-left: var(#{$variable}) !important;
}
.mr-#{$index} {
margin-right: var(#{$variable}) !important;
}
.p-#{$index} {
padding: var(#{$variable}) !important;
}
.px-#{$index} {
padding-left: var(#{$variable}) !important;
padding-right: var(#{$variable}) !important;
}
.py-#{$index} {
padding-top: var(#{$variable}) !important;
padding-bottom: var(#{$variable}) !important;
}
.pt-#{$index} {
padding-top: var(#{$variable}) !important;
}
.pb-#{$index} {
padding-bottom: var(#{$variable}) !important;
}
.pl-#{$index} {
padding-left: var(#{$variable}) !important;
}
.pr-#{$index} {
padding-right: var(#{$variable}) !important;
@include spacing-utils($index, var(#{$variable}));
@include mixins.responsive using($screen-size) {
@include spacing-utils($index, var(#{$variable}), $screen-size);
}
}

View file

@ -8,7 +8,7 @@ const links = [
];
---
<nav class="navbar navbar-expand-lg bg-body-tertiary">
<nav class="navbar d-none d-lg-block">
<ul class="list-unstyle hstack">
{
links.map((link) => (
@ -22,20 +22,112 @@ const links = [
</ul>
</nav>
<div class="text-end d-lg-none">
<button id="btn-toggle" class="off-canvas-toggle" data-target="#mobile-nav">
<svg
width="40px"
height="40px"
viewBox="-2.4 -2.4 28.80 28.80"
fill="none"
xmlns="http://www.w3.org/2000/svg"
stroke=""
stroke-width="0.00024000000000000003"
transform="rotate(0)"
><g
id="SVGRepo_bgCarrier"
stroke-width="0"
transform="translate(1.1999999999999993,1.1999999999999993), scale(0.9)"
><rect
x="-2.4"
y="-2.4"
width="28.80"
height="28.80"
rx="2.88"
fill="none"
strokewidth="0"></rect></g
><g
id="SVGRepo_tracerCarrier"
stroke-linecap="round"
stroke-linejoin="round"
stroke="#CCCCCC"
stroke-width="0.384"></g><g id="SVGRepo_iconCarrier">
<path
d="M2 5.5C2 4.94772 2.44772 4.5 3 4.5H21C21.5523 4.5 22 4.94772 22 5.5V6.5C22 7.05228 21.5523 7.5 21 7.5H3C2.44772 7.5 2 7.05228 2 6.5V5.5Z"
fill="#cad3f5"></path>
<path
d="M2 11.5C2 10.9477 2.44772 10.5 3 10.5H21C21.5523 10.5 22 10.9477 22 11.5V12.5C22 13.0523 21.5523 13.5 21 13.5H3C2.44772 13.5 2 13.0523 2 12.5V11.5Z"
fill="#cad3f5"></path>
<path
d="M3 16.5C2.44772 16.5 2 16.9477 2 17.5V18.5C2 19.0523 2.44772 19.5 3 19.5H21C21.5523 19.5 22 19.0523 22 18.5V17.5C22 16.9477 21.5523 16.5 21 16.5H3Z"
fill="#cad3f5"></path>
</g></svg
>
<span class="visually-hidden">Open sidebar</span>
</button>
<div id="mobile-nav" class="off-canvas">
<div class="off-canvas-content">
<button class="off-canvas-toggle" data-target="#mobile-nav">
<svg
width="40px"
height="40px"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
fill="#ffffff"
><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g
id="SVGRepo_tracerCarrier"
stroke-linecap="round"
stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"
><path
fill="#cad3f5"
d="M195.2 195.2a64 64 0 0 1 90.496 0L512 421.504 738.304 195.2a64 64 0 0 1 90.496 90.496L602.496 512 828.8 738.304a64 64 0 0 1-90.496 90.496L512 602.496 285.696 828.8a64 64 0 0 1-90.496-90.496L421.504 512 195.2 285.696a64 64 0 0 1 0-90.496z"
></path></g
></svg
>
</button>
<nav class="navbar">
<ul class="list-unstyle text-start">
{
links.map((link) => (
<li class="nav-item mb-3">
<a class="nav-link" href={link.href}>
{link.text}
</a>
</li>
))
}
</ul>
</nav>
</div>
<div class="off-canvas-backdrop"></div>
</div>
</div>
<script>
const setActiveLink = () => {
const link = document.querySelector(`a[href='${location.pathname}']`);
const links = document.querySelectorAll(`a[href='${location.pathname}']`);
if (link) {
link.classList.add('active');
}
links.forEach((link) => link.classList.add('active'));
};
// Add active class to the current link
document.addEventListener('astro:page-load', setActiveLink, { once: true });
document.addEventListener('astro:after-swap', setActiveLink);
document.querySelectorAll('.off-canvas-toggle').forEach((btn) =>
btn.addEventListener('click', (e) => {
const { target } = btn.dataset;
if (!target) return;
document.querySelector(target)?.classList.toggle('active');
}),
);
</script>
<style>
<style lang="scss">
nav {
width: fit-content;
}
@ -67,4 +159,60 @@ const links = [
color: var(--prj-accent-text);
border: 1px solid var(--border-color);
}
.off-canvas-toggle {
width: 40px;
height: 40px;
padding: 0;
border: none;
background: none;
cursor: pointer;
}
.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;
}
}
</style>

View file

@ -45,7 +45,7 @@ const portafolio = await getCollection('portafolio', ({ data }) =>
<section>
<h2 class="text-center">Featured Work</h2>
<div class="grid grid-cols-3 gap-4">
<div class="grid grid-cols-1 grid-lg-cols-3 gap-4">
<Card>
<img
src="https://placehold.co/600x400"
@ -189,7 +189,7 @@ const portafolio = await getCollection('portafolio', ({ data }) =>
>
<h2 class="text-center">Who am I?</h2>
<p class="w-70 mx-auto text-justify">
<p class="w-95 w-lg-70 mx-auto text-justify">
Lorem ipsum dolor sit amet, officia excepteur ex fugiat reprehenderit enim
labore culpa sint ad nisi Lorem pariatur mollit ex esse exercitation amet.
Nisi anim cupidatat excepteur officia. Reprehenderit nostrud nostrud ipsum
@ -212,7 +212,7 @@ const portafolio = await getCollection('portafolio', ({ data }) =>
<section>
<h2>Contact</h2>
<div class="grid grid-cols-2">
<div class="grid grid-cols-1 grid-lg-cols-2">
<div>
<div class="text-center">
<img
@ -230,24 +230,43 @@ const portafolio = await getCollection('portafolio', ({ data }) =>
</div>
<div class="vstack justify-content-center">
<ul class="list-unstyle fs-5 ml-5">
<li class="mb-3">
<a href="" class="hstack gap-2"
><img src="https://placehold.co/60" alt="" /><span>Github</span
></a
>
</li>
<li class="mb-3">
<a href="" class="hstack gap-2"
><img src="https://placehold.co/60" alt="" /><span>Linkedin</span
></a
>
</li>
<li class="mb-3">
<a href="" class="hstack gap-2"
><img src="https://placehold.co/60" alt="" /><span>Email</span></a
>
</li>
<ul
class="list-unstyle fs-5 ml-lg-5 mt-3 d-flex d-lg-block justify-content-around"
>
{
[
{
link: '#',
img: 'https://placehold.co/60',
alt: '',
text: 'Github',
},
{
link: '#',
img: 'https://placehold.co/60',
alt: '',
text: 'Linkedin',
},
{
link: '#',
img: 'https://placehold.co/60',
alt: '',
text: 'Email',
},
].map((item) => (
<li class="mb-3">
<a
href={item.link}
class="hstack flex-column flex-lg-row gap-2"
>
<>
<img src={item.img} alt={item.alt} />
<span>{item.text}</span>
</>
</a>
</li>
))
}
</ul>
</div>
</div>