Sidebar y styles

This commit is contained in:
jorgemike
2025-03-22 21:07:27 -05:00
parent a6a83fe65a
commit d4b896bba3
17 changed files with 808 additions and 61 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 223 KiB

+1 -1
View File
@@ -82,7 +82,7 @@ export default function Page() {
<section className="mb-5" id="input-props">
<h2 className="h5 mb-3">Props del componente</h2>
<table className="table table-bordered table-striped align-middle">
<table className="table align-middle">
<thead>
<tr>
<th scope="col">Prop</th>
+4 -4
View File
@@ -26,7 +26,7 @@ export default function Page() {
/>
<div className="my-5">
<h1 className="mb-4 display-5">
📑 Componente: <code>Select</code>
Componente: <code>Select</code>
</h1>
<p className="mb-4 text-muted">
@@ -38,7 +38,7 @@ export default function Page() {
<hr className="my-5" />
<VistaComponente
title="🌍 Select básico"
title="Select básico"
description="Un select controlado con opciones simples y un placeholder deshabilitado."
code={countrySelectSnippet}
id="select-basico"
@@ -54,7 +54,7 @@ export default function Page() {
</VistaComponente>
<VistaComponente
title="🎨 Personalización de estilos"
title="Personalización de estilos"
description="Puedes aplicar clases personalizadas al contenedor, etiqueta o al select."
code={languageSelectSnippet}
id="select-estilos"
@@ -77,7 +77,7 @@ export default function Page() {
</VistaComponente>
<section className="mb-5">
<h2 className="h5"> Props del componente</h2>
<h2 className="h5">Props del componente</h2>
<ul>
<li>
<code>label: string</code> Etiqueta visible del campo.
+229
View File
@@ -0,0 +1,229 @@
"use client";
import IndiceContenido from "@/components/content-index";
import Sidebar, { SidebarLink } from "@/components/sidebar";
import VistaComponente from "@/components/vista-componente";
import React from "react";
const basicLinks: SidebarLink[] = [
{ icon: "bi-house", text: "Inicio", href: "/inicio" },
{
icon: "bi-person",
text: "Perfil",
href: "/perfil",
className: "hover-bg-success",
},
{
icon: "bi-envelope",
text: "Mensajes",
href: "/mensajes",
className: "hover-bg-info",
},
{
icon: "bi-gear",
text: "Configuración",
href: "/configuracion",
className: "hover-bg-warning",
},
{
icon: "bi-bar-chart",
text: "Reportes",
href: "/reportes",
className: "hover-bg-danger",
},
];
const onClickLinks: SidebarLink[] = [
{
icon: "bi-lightning",
text: "Acción rápida",
onClick: () => alert("¡Ejecutando acción rápida!"),
className: "hover-bg-warning text-warning",
},
{
icon: "bi-question-circle",
text: "Ayuda",
onClick: () => alert("Mostrando ayuda..."),
className: "hover-bg-info text-info",
},
{
icon: "bi-bell",
text: "Notificaciones",
onClick: () => alert("Mostrando notificaciones..."),
className: "hover-bg-primary text-primary",
},
];
const renderItems: SidebarLink[] = [
{
render: () => (
<li className="nav-item">
<div className="nav-link text-success">
<i className="bi bi-star-fill me-2"></i>
<span>Componente especial</span>
</div>
</li>
),
},
{
render: () => (
<li className="nav-item">
<div className="nav-link text-primary">
<i className="bi bi-heart-fill me-2"></i>
<span>Favoritos</span>
</div>
</li>
),
},
{
render: () => (
<li className="nav-item hover-bg-danger">
<div className="nav-link text-danger">
<i className="bi bi-exclamation-circle-fill me-2"></i>
<span>Alertas</span>
</div>
</li>
),
},
{
render: () => (
<li className="nav-item">
<div className="nav-link text-warning">
<i className="bi bi-lightbulb-fill me-2"></i>
<span>Ideas</span>
</div>
</li>
),
},
];
export default function Page() {
return (
<>
<IndiceContenido
items={[
{ id: "sidebar-ejemplo", label: "Sidebar básico" },
{ id: "sidebar-acciones", label: "Sidebar con acciones" },
{
id: "sidebar-render-items",
label: "Sidebar con elementos personalizados",
},
{
id: "sidebar-colores",
label: "Sidebar con personalización de colores",
},
]}
/>
<div className="my-5">
<h1 className="mb-4 display-5">
Componente: <code>Sidebar</code>
</h1>
<p className="mb-4 text-muted">
El <code>Sidebar</code> es un componente versátil que funciona como un
menú lateral adaptable, diseñado para ser accesible tanto en
dispositivos móviles como en pantallas de escritorio. Permite incluir
enlaces, acciones personalizadas, colores personalizables por clase y
elementos renderizados dinámicamente.
</p>
<hr className="my-5"/>
<VistaComponente
title="Sidebar básico"
description="Un ejemplo básico de un componente de menú lateral con opciones simples."
id="sidebar-ejemplo"
>
<div className="d-lg-flex">
<Sidebar
id="sidebar"
userName="Usuario"
userRole="Administrador"
appTitle="Sistema de Encuestas"
logoSrc="/unam.png"
links={basicLinks}
/>
<main className="flex-grow-1 p-4 border rounded">
</main>
</div>
</VistaComponente>
<VistaComponente
title="Sidebar con acciones"
description="Menú lateral con enlaces que ejecutan funciones al hacer clic."
id="sidebar-acciones"
>
<div className="d-lg-flex">
<Sidebar
id="sidebar-acciones"
userName="Usuario"
userRole="Administrador"
appTitle="Sistema de Encuestas"
logoSrc="/unam.png"
links={onClickLinks}
/>
<main className="flex-grow-1 p-4 border rounded">
<h1>Contenido interactivo</h1>
<p>
Cada enlace ejecuta una acción mediante <code>onClick</code>.
Este patrón es útil para accesos rápidos o elementos no
vinculados a rutas.
</p>
</main>
</div>
</VistaComponente>
<VistaComponente
title="Sidebar con elementos personalizados"
description="Uso de la propiedad render para incluir componentes únicos dentro del menú."
id="sidebar-render-items"
>
<div className="d-lg-flex">
<Sidebar
id="sidebar-render-items"
userName="Usuario"
userRole="Administrador"
appTitle="Sistema de Encuestas"
logoSrc="/unam.png"
links={renderItems}
/>
<main className="flex-grow-1 p-4 border rounded">
<h1>Elementos renderizados</h1>
<p>
La propiedad <code>render</code> permite insertar cualquier JSX
personalizado dentro del menú, ideal para incluir botones,
badges o estados especiales.
</p>
</main>
</div>
</VistaComponente>
<VistaComponente
title="Sidebar con personalización de colores"
description="Cada enlace puede tener un color diferente en hover usando clases utilitarias como hover-bg-warning, hover-bg-danger, etc."
id="sidebar-colores"
>
<div className="d-lg-flex">
<Sidebar
id="sidebar-colores"
userName="Usuario"
userRole="Administrador"
appTitle="Sistema de Encuestas"
logoSrc="/unam.png"
links={[...basicLinks, ...onClickLinks]}
/>
<main className="flex-grow-1 p-4 border rounded">
<h1>Hover personalizados</h1>
<p>
Gracias a las clases <code>hover-bg-COLOR</code> generadas a
partir de <code>$theme-colors</code>, cada elemento del menú
puede mostrar un color diferente al pasar el cursor.
</p>
</main>
</div>
</VistaComponente>
</div>
</>
);
}
+134
View File
@@ -0,0 +1,134 @@
"use client";
import React from "react";
import IndiceContenido from "@/components/content-index";
import VistaComponente from "@/components/vista-componente";
export default function Page() {
return (
<>
<IndiceContenido
items={[
{ id: "box", label: "Box" },
{ id: "gradients", label: "Gradientes" },
{ id: "scale-hover", label: "Escala al pasar el cursor" },
{ id: "hover-bg", label: "Color de fondo al pasar el cursor" },
]}
/>
<div className="my-5">
<h1 className="mb-4 display-5">Estilos</h1>
<p className="mb-4 text-muted">
Los estilos de la aplicación se basan en Bootstrap 5 y se personalizan
mediante clases SCSS para mantener una apariencia coherente y
flexible.
</p>
<hr className="my-5" />
<div className="alert alert-info">
<i className="bi bi-info-circle me-2"></i>
Leer la documentación de <code>.box</code>
</div>
<VistaComponente
id="box"
title="Estilo: Box"
description="Un contenedor con bordes redondeados y sombra suave para destacar contenido. La mayoria del sistema usa este estilo, por loq ue si lo modificas muy seguramente estarias modificando la apariencia de toda la aplicacion."
code={`<div className="box">
<h1><code>div</code> con className <code>.box</code></h1>
</div>`}
>
<div className="box mb-3">
<h1 className="mb-0">
<code>div</code> con className <code>.box</code>
</h1>
</div>
</VistaComponente>
<VistaComponente
id="gradients"
title="Estilo: bg-gradient"
description="Genera un fondo con gradiente en diferentes direcciones utilizando los colores del tema. Cada clase aplica una transición de color hacia el fondo general de la página (<code>$body-bg</code>). Este estilo se usa también en la página de inicio con el color azul. si se desea que el color sea mas fuerte se puede modificar en @/styles/sass/_gradients.scss"
code={`<div className="bg-gradient-{variante}-{posicion} p-4 text-white">
Gradiente desde arriba (top) con color primario
</div>`}
>
<div className="bg-gradient-primary-top p-3 mb-3 rounded text-white">
Gradiente desde arriba (top) con color primario
</div>
<div className="bg-gradient-success-right p-3 mb-3 rounded text-white">
Gradiente desde la derecha (right) con color success
</div>
<div className="bg-gradient-warning-bottom p-3 mb-3 rounded text-white">
Gradiente desde abajo (bottom) con color warning
</div>
<div className="bg-gradient-info-left p-3 mb-3 rounded text-white text-end">
Gradiente desde la izquierda (left) con color info
</div>
<h2 className="mt-4 h5">Ejemplo de gradiente de Bootstrap 5</h2>
<p className="text-muted">
Bootstrap incluye su propio estilo <code>.bg-gradient</code> que
aplica un efecto sutil sobre el fondo.
</p>
<div className="bg-primary bg-gradient p-3 text-white rounded mb-3">
Fondo con <code>.bg-primary.bg-gradient</code>
</div>
</VistaComponente>
<VistaComponente
id="scale-hover"
title="Utilidad: scale-hover"
description="Estas clases aplican una transformación <code>scale</code> al pasar el cursor, generando un efecto de ampliación suave. Útil para botones, tarjetas u otros elementos interactivos."
code={`<div className="scale-hover-1">Escala 1.05</div>
<div className="scale-hover-3">Escala 1.15</div>
<div className="scale-hover-5">Escala 1.25</div>`}
>
<div className="d-flex flex-wrap gap-3 mb-3">
{[1, 2, 3, 4, 5].map((scale) => (
<div
key={scale}
className={`scale-hover-${scale} p-3 border rounded text-center`}
style={{ width: "150px" }}
>
<strong>{`scale-hover-${scale}`}</strong>
<br />({(1 + scale * 0.05).toFixed(2)}x)
</div>
))}
</div>
</VistaComponente>
<VistaComponente
id="hover-bg"
title="Utilidad: hover-bg"
description="Clases que aplican un color de fondo semitransparente en estado <code>:hover</code> o cuando el elemento tiene la clase <code>.active</code>. Se pueden usar en tarjetas, botones personalizados o elementos de navegación. Además, si contienen un elemento con clase <code>.nav-link</code>, su color se forzará a blanco."
code={`<div className="hover-bg-primary p-3">Hover primario</div>
<div className="hover-bg-success p-3 active">Elemento activo con fondo success</div>`}
>
<div className="d-flex flex-wrap gap-3">
{["primary", "success", "warning", "danger", "azul"].map(
(color) => (
<div
key={color}
className={`hover-bg-${color} p-3 border rounded text-center`}
style={{ width: "180px" }}
>
<strong>{`hover-bg-${color}`}</strong>
<br />
{color === "primary" && "(hover o active)"}
</div>
)
)}
</div>
<h2 className="mt-4 h6">
Ejemplo con <code>.nav-link</code>
</h2>
<div className="hover-bg-primary p-3 rounded mb-3">
<a className="nav-link" href="#">
Enlace dentro de hover-bg-primary
</a>
</div>
</VistaComponente>
</div>
</>
);
}
+1 -1
View File
@@ -224,7 +224,7 @@ export default function Page() {
{/* PROPS */}
<section className="mb-5" id="props-del-componente">
<h2 className="h5 mb-3">Props del componente</h2>
<table className="table table-bordered table-striped align-middle">
<table className="table align-middle overflow-auto">
<thead>
<tr>
<th scope="col">Prop</th>
+3
View File
@@ -3,6 +3,8 @@ import { Roboto } from "next/font/google";
import 'bootstrap-icons/font/bootstrap-icons.css';
import '@/styles/sass/bootstrap.scss';
import BootstrapClient from "@/components/bootstrap-client";
import Navbar from "@/components/navbar";
const roboto = Roboto({
@@ -26,6 +28,7 @@ export default function RootLayout({
return (
<html lang="en">
<body className={`${roboto.className}`}>
<BootstrapClient />
<Navbar />
{children}
</body>
+63 -9
View File
@@ -1,11 +1,14 @@
"use client";
import ComponentCard from "@/components/component-card";
import Image from "next/image";
import React from "react";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { vscDarkPlus } from "react-syntax-highlighter/dist/cjs/styles/prism";
export default function Page() {
return (
<main className="">
<main>
<div className="container-fluid bg-gradient-primary-bottom text-center py-5">
<div className="mt-4">
<Image
@@ -16,10 +19,62 @@ export default function Page() {
className="img-fluid"
/>
</div>
<h1 className="display-3 fw-bold text-azul">Libreria de componentes de CIDWA</h1>
<h1 className="display-3 fw-bold text-azul">
Librería de componentes de CIDWA
</h1>
</div>
<div className="container">
<h2>Componentes</h2>
<div className="container py-4">
<h1>Uso de componentes</h1>
<p>
Esta librería ofrece una colección de componentes reutilizables, diseñados según las guías de estilo de CIDWA, para facilitar la construcción de interfaces consistentes y accesibles.
</p>
<hr />
<h2>Instalación</h2>
<p>
Para comenzar a utilizar los componentes, primero instala las siguientes dependencias:
</p>
<SyntaxHighlighter language="bash" style={vscDarkPlus} customStyle={{ borderRadius: "10px" }}>
{`npm i bootstrap bootstrap-icons
npm i -D sass`}
</SyntaxHighlighter>
<p>
Luego, copia las carpetas <code>components</code> y <code>styles</code> dentro de tu directorio <code>src</code>. Estas contienen los componentes y estilos necesarios (SCSS y CSS).
</p>
<h2>Configuración</h2>
<p>
Asegúrate de importar los estilos y el componente <code>BootstrapClient</code> en tu archivo <code>layout.tsx</code>, como se muestra a continuación:
</p>
<SyntaxHighlighter language="typescript" style={vscDarkPlus} customStyle={{ borderRadius: "10px" }}>
{`import 'bootstrap-icons/font/bootstrap-icons.css';
import '@/styles/sass/bootstrap.scss';
import BootstrapClient from "@/components/bootstrap-client";`}
</SyntaxHighlighter>
<p>
Es importante incluir el componente <code>BootstrapClient</code> para que los scripts de Bootstrap se carguen correctamente y sus componentes interactivos funcionen como se espera.
</p>
<p>Aquí tienes un ejemplo del uso dentro del layout:</p>
<SyntaxHighlighter language="tsx" style={vscDarkPlus} customStyle={{ borderRadius: "10px" }}>
{`<html lang="en">
<body className={\`\${roboto.className}\`}>
<BootstrapClient />
{children}
</body>
</html>`}
</SyntaxHighlighter>
<hr />
<h2>Componentes disponibles</h2>
<div className="row row-gap-4">
<div className="col-lg-4">
<ComponentCard title="Table" src="/table.png" href="table" />
@@ -28,11 +83,7 @@ export default function Page() {
<ComponentCard title="Input" src="/input.png" href="input" />
</div>
<div className="col-lg-4">
<ComponentCard
title="Pagination"
src="/pagination.png"
href="pagination"
/>
<ComponentCard title="Pagination" src="/pagination.png" href="pagination" />
</div>
<div className="col-lg-4">
<ComponentCard title="Options" src="/options.png" href="options" />
@@ -40,6 +91,9 @@ export default function Page() {
<div className="col-lg-4">
<ComponentCard title="Select" src="/select.png" href="select" />
</div>
<div className="col-lg-4">
<ComponentCard title="Sidebar" src="/sidebar.png" href="sidebar" />
</div>
</div>
</div>
</main>
+17
View File
@@ -0,0 +1,17 @@
'use client';
import { useEffect } from 'react';
export default function BootstrapClient() {
useEffect(() => {
const loadBootstrap = async () => {
if (typeof document !== 'undefined') {
// @ts-expect-error: Bootstrap is loaded dynamically
await import('bootstrap/dist/js/bootstrap.bundle.min.js');
}
};
loadBootstrap();
}, []);
return null;
}
+60 -33
View File
@@ -5,39 +5,66 @@ const Navbar: React.FC = () => {
return (
<nav className="navbar navbar-expand-lg navbar-light bg-transparent fixed-top">
<div className="container">
<div className="mx-auto">
<ul className="navbar-nav gap-5">
<li className="nav-item">
<Link className="nav-link" href="/">
Inicio
</Link>
</li>
<li className="nav-item">
<Link className="nav-link" href="/table">
Table
</Link>
</li>
<li className="nav-item">
<Link className="nav-link" href="/input">
Input
</Link>
</li>
<li className="nav-item">
<Link className="nav-link" href="/pagination">
Pagination
</Link>
</li>
<li className="nav-item">
<Link className="nav-link" href="/options">
Options
</Link>
</li>
<li className="nav-item">
<Link className="nav-link" href="/select">
Select
</Link>
</li>
</ul>
<button
className="navbar-toggler border-0 ms-auto"
type="button"
data-bs-toggle="offcanvas"
data-bs-target="#offcanvasNavbar"
aria-controls="offcanvasNavbar"
>
<span className="navbar-toggler-icon"></span>
</button>
<div
className="offcanvas offcanvas-end"
tabIndex={-1}
id="offcanvasNavbar"
aria-labelledby="offcanvasNavbarLabel"
>
<div className="offcanvas-header">
<h5 className="offcanvas-title" id="offcanvasNavbarLabel">
Menu
</h5>
<button
type="button"
className="btn-close"
data-bs-dismiss="offcanvas"
aria-label="Close"
></button>
</div>
<div className="offcanvas-body justify-content-center">
<ul className="navbar-nav gap-lg-5">
<li className="nav-item" data-bs-dismiss="offcanvas">
<Link className="nav-link" href="/">
Inicio
</Link>
</li>
<li className="nav-item" data-bs-dismiss="offcanvas">
<Link className="nav-link" href="/table">
Table
</Link>
</li>
<li className="nav-item" data-bs-dismiss="offcanvas">
<Link className="nav-link" href="/input">
Input
</Link>
</li>
<li className="nav-item" data-bs-dismiss="offcanvas">
<Link className="nav-link" href="/pagination">
Pagination
</Link>
</li>
<li className="nav-item" data-bs-dismiss="offcanvas">
<Link className="nav-link" href="/options">
Options
</Link>
</li>
<li className="nav-item" data-bs-dismiss="offcanvas">
<Link className="nav-link" href="/styles">
Styles
</Link>
</li>
</ul>
</div>
</div>
</div>
</nav>
+174
View File
@@ -0,0 +1,174 @@
"use client";
import Image from "next/image";
import Link from "next/link";
import { usePathname } from "next/navigation";
import React, { useEffect, useState } from "react";
export interface SidebarLink {
icon?: string;
text?: string;
href?: string;
show?: boolean;
className?: string;
onClick?: () => void;
render?: () => React.ReactNode;
}
interface SidebarProps {
id: string;
userName?: string;
userRole?: string;
logoSrc?: string;
appTitle?: string;
links: SidebarLink[];
}
export default function Sidebar({
userName = "Usuario",
userRole = "Administrador",
logoSrc = "/unam.png",
appTitle = "Sistema de -------",
links,
id,
}: SidebarProps) {
const pathname = usePathname();
const [isOpen, setIsOpen] = useState(false);
useEffect(() => {
const open = localStorage.getItem(id) === "true";
setIsOpen(open);
}, [id]);
const toggleSidebar = () => {
localStorage.setItem(id, `${!isOpen}`);
setIsOpen(!isOpen);
};
return (
<aside className={`sidebar ${isOpen ? "open" : "close"}`}>
{/* Header for mobile */}
<div className="d-flex justify-content-between align-items-center p-2 d-lg-none">
<h1 className="h3 m-0">{appTitle}</h1>
<button
type="button"
className="m-0 p-0 border-0 bg-transparent"
data-bs-toggle="offcanvas"
data-bs-target={`#${id}-offcanvas`}
aria-controls={`${id}-offcanvas`}
>
<i className="bi bi-list fs-2"></i>
</button>
</div>
<div
className="offcanvas-lg offcanvas-end"
tabIndex={-1}
id={`${id}-offcanvas`}
aria-labelledby={`${id}-offcanvas-label`}
>
<div className="offcanvas-header">
<h5 className="offcanvas-title" id={`${id}-offcanvas-label`}>
{appTitle}
</h5>
<button
type="button"
className="btn-close"
data-bs-dismiss="offcanvas"
data-bs-target={`#${id}-offcanvas`}
aria-label="Close"
/>
</div>
<div className="offcanvas-body position-relative">
{/* Toggle sidebar button */}
<div
className="d-none d-lg-flex position-absolute"
style={{ top: "0", right: "-2rem" }}
>
<button
className="bg-white border-0 shadow-sm px-2 py-1"
type="button"
onClick={toggleSidebar}
>
<i
className={`bi bi-layout-sidebar-${
isOpen ? "inset" : "inset-reverse"
} text-muted`}
></i>
</button>
</div>
<div>
{/* User Info */}
<div className="d-flex align-items-center gap-3 my-2">
<Image src={logoSrc} width={40} height={40} alt="Logo" />
<div className="nav-link">
<span>
<b>{userName}</b>
<br />
<p className="text-muted m-0">{userRole}</p>
</span>
</div>
</div>
<hr />
<ul className="nav flex-column gap-2">
{links
.filter((link) => link.show !== false)
.map((link, index) => {
if (link.render) {
return (
<React.Fragment key={index}>
{link.render()}
</React.Fragment>
);
}
const isActive =
!!link.href &&
(pathname === link.href ||
(pathname?.startsWith(link.href) && link.href !== "/u"));
const baseClass = `nav-item ${isActive ? "active" : ""} ${
link.className || ""
}`;
return (
<li
key={index}
className={baseClass}
data-tooltip={link.text}
data-bs-dismiss="offcanvas"
data-bs-target="#offcanvasResponsive"
aria-label="Close"
>
{link.href ? (
<Link
href={link.href}
className="nav-link"
onClick={link.onClick}
>
{link.icon && <i className={`bi ${link.icon}`}></i>}
<span>{link.text}</span>
</Link>
) : (
<button
className="nav-link w-100 text-start"
onClick={link.onClick}
>
{link.icon && <i className={`bi ${link.icon}`}></i>}
<span>{link.text}</span>
</button>
)}
</li>
);
})}
</ul>
</div>
</div>
</div>
</aside>
);
}
View File
+1 -1
View File
@@ -11,7 +11,7 @@
.bg-gradient-#{$color-name}-bottom {
background-image: linear-gradient(
to bottom,
rgba($color-value, 0.3),
rgba($color-value, 0.5),
$body-bg
);
}
+15
View File
@@ -0,0 +1,15 @@
// Clases personalizadas de hover por color
@each $name, $color in $theme-colors {
.hover-bg-#{$name} {
transition: background-color 0.4s;
&:hover,
&.active {
background-color: rgba($color, 0.75) !important;
.nav-link {
color: #ffffff !important;
}
}
}
}
+90
View File
@@ -0,0 +1,90 @@
.sidebar {
@extend .py-0;
@extend .box;
@extend .m-lg-2;
.nav-item {
@extend .rounded-pill;
@extend .w-100;
transition: background-color 0.4s;
// Hover por defecto (solo si no tiene clase hover-bg-*)
&:not([class*="hover-bg-"]):hover,
&:not([class*="hover-bg-"]).active {
@extend .bg-primary;
@extend .bg-opacity-75;
.nav-link {
color: #ffffff !important;
}
}
.nav-link {
i {
@extend .me-2;
}
}
}
@include media-breakpoint-up(lg) {
@extend .py-lg-2;
position: sticky;
top: 0;
left: 0;
width: clamp(250px, 100%, 300px);
max-width: 300px;
transition: width 0.3s ease;
.offcanvas-body {
display: block;
}
&.open {
.nav-link {
overflow: hidden;
white-space: nowrap;
span {
transition: opacity 0.3s, visibility 0.3s;
opacity: 1;
visibility: visible;
}
}
}
&.close {
width: 80px;
.nav-item:hover {
position: relative;
&::after {
content: attr(data-tooltip);
position: absolute;
top: 50%;
left: 100%;
transform: translate(10px, -50%);
background-color: rgba(0, 0, 0, 0.7);
color: white;
padding: 5px 10px;
border-radius: 5px;
opacity: 0;
animation: fadeInOut 4s ease-in-out;
font-style: normal;
max-width: 200px;
}
}
.nav-link {
overflow: hidden;
white-space: nowrap;
span {
transition: opacity 0.3s, visibility 0.3s;
opacity: 0;
visibility: hidden;
}
}
}
}
}
+16 -12
View File
@@ -16,31 +16,35 @@ $custom-colors: (
$theme-colors: map-merge($theme-colors, $custom-colors);
@import "gradients";
@import "extends";
@import "table";
@import "utilities";
@import "bootstrap/scss/maps";
@import "bootstrap/scss/mixins";
@import "bootstrap/scss/bootstrap";
@import "gradients";
@import "extends";
@import "table";
@import "utilities";
@import 'sidebar';
@import 'hover';
//Add additional custom code here
@media (min-width: 992px) {
@include media-breakpoint-up(lg) {
.bd-layout {
display: grid;
grid-template-areas: "sidebar main";
grid-template-columns: 1fr 5fr;
gap: 1.5rem;
gap: $spacer * 1.5;
}
}
.bd-sidebar {
grid-area: sidebar;
position: sticky;
top: ($spacer * 3);
height: calc(100vh - 6rem);
@include media-breakpoint-up(lg) {
.bd-sidebar {
grid-area: sidebar;
position: sticky;
top: ($spacer * 3);
height: calc(100vh - 6rem);
}
}
ul.list-unstyled li {