first commit

This commit is contained in:
2025-03-07 00:29:07 -06:00
commit b21a11c2ee
564 changed files with 94041 additions and 0 deletions

View File

@ -0,0 +1,129 @@
/*
* demo.css
* File include item demo only specific css only
******************************************************************************/
.light-style .menu .app-brand.demo {
height: 64px;
}
.dark-style .menu .app-brand.demo {
height: 64px;
}
.app-brand-logo.demo {
-ms-flex-align: center;
align-items: center;
-ms-flex-pack: center;
justify-content: center;
display: -ms-flexbox;
display: flex;
width: 34px;
height: 24px;
}
.app-brand-logo.demo svg {
width: 35px;
height: 24px;
}
.app-brand-text.demo {
font-size: 1.375rem;
}
/* ! For .layout-navbar-fixed added fix padding top tpo .layout-page */
.layout-navbar-fixed .layout-wrapper:not(.layout-without-menu) .layout-page {
padding-top: 64px !important;
}
.layout-navbar-fixed .layout-wrapper:not(.layout-horizontal):not(.layout-without-menu) .layout-page {
padding-top: 72px !important;
}
/* Navbar page z-index issue solution */
.content-wrapper .navbar {
z-index: auto;
}
/*
* Content
******************************************************************************/
.demo-blocks > * {
display: block !important;
}
.demo-inline-spacing > * {
margin: 1rem 0.375rem 0 0 !important;
}
/* ? .demo-vertical-spacing class is used to have vertical margins between elements. To remove margin-top from the first-child, use .demo-only-element class with .demo-vertical-spacing class. For example, we have used this class in forms-input-groups.html file. */
.demo-vertical-spacing > * {
margin-top: 1rem !important;
margin-bottom: 0 !important;
}
.demo-vertical-spacing.demo-only-element > :first-child {
margin-top: 0 !important;
}
.demo-vertical-spacing-lg > * {
margin-top: 1.875rem !important;
margin-bottom: 0 !important;
}
.demo-vertical-spacing-lg.demo-only-element > :first-child {
margin-top: 0 !important;
}
.demo-vertical-spacing-xl > * {
margin-top: 5rem !important;
margin-bottom: 0 !important;
}
.demo-vertical-spacing-xl.demo-only-element > :first-child {
margin-top: 0 !important;
}
.rtl-only {
display: none !important;
text-align: left !important;
direction: ltr !important;
}
[dir='rtl'] .rtl-only {
display: block !important;
}
/* Dropdown buttons going out of small screens */
@media (max-width: 576px) {
#dropdown-variation-demo .btn-group .text-truncate {
width: 254px;
position: relative;
}
#dropdown-variation-demo .btn-group .text-truncate::after {
position: absolute;
top: 45%;
right: 0.65rem;
}
}
/*
* Layout demo
******************************************************************************/
.layout-demo-wrapper {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
margin-top: 1rem;
}
.layout-demo-placeholder img {
width: 900px;
}
.layout-demo-info {
text-align: center;
margin-top: 1rem;
}

View File

@ -0,0 +1,245 @@
import '../../vendor/libs/bootstrap-table/bootstrap-table';
import '../notifications/LivewireNotification';
class BootstrapTableManager {
constructor(bootstrapTableWrap, config = {}) {
const defaultConfig = {
header: [],
format: [],
search_columns: [],
actionColumn: false,
height: 'auto',
minHeight: 300,
bottomMargin : 195,
search: true,
showColumns: true,
showColumnsToggleAll: true,
showExport: true,
exportfileName: 'datatTable',
exportWithDatetime: true,
showFullscreen: true,
showPaginationSwitch: true,
showRefresh: true,
showToggle: true,
/*
smartDisplay: false,
searchOnEnterKey: true,
showHeader: false,
showFooter: true,
showRefresh: true,
showToggle: true,
showFullscreen: true,
detailView: true,
searchAlign: 'right',
buttonsAlign: 'right',
toolbarAlign: 'left',
paginationVAlign: 'bottom',
paginationHAlign: 'right',
paginationDetailHAlign: 'left',
paginationSuccessivelySize: 5,
paginationPagesBySide: 3,
paginationUseIntermediate: true,
*/
clickToSelect: true,
minimumCountColumns: 4,
fixedColumns: true,
fixedNumber: 1,
idField: 'id',
pagination: true,
pageList: [25, 50, 100, 500, 1000],
sortName: 'id',
sortOrder: 'asc',
cookie: false,
cookieExpire: '365d',
cookieIdTable: 'myTableCookies', // Nombre único para las cookies de la tabla
cookieStorage: 'localStorage',
cookiePath: '/',
};
this.$bootstrapTable = $('.bootstrap-table', bootstrapTableWrap);
this.$toolbar = $('.bt-toolbar', bootstrapTableWrap);
this.$searchColumns = $('.search_columns', bootstrapTableWrap);
this.$btnRefresh = $('.btn-refresh', bootstrapTableWrap);
this.$btnClearFilters = $('.btn-clear-filters', bootstrapTableWrap);
this.config = { ...defaultConfig, ...config };
this.config.toolbar = `${bootstrapTableWrap} .bt-toolbar`;
this.config.height = this.config.height == 'auto'? this.getTableHeight(): this.config.height;
this.config.cookieIdTable = this.config.exportWithDatetime? this.config.cookieIdTable + '-' + this.getFormattedDateYMDHm(): this.config.cookieIdTable;
this.tableFormatters = {}; // Mueve la carga de formatters aquí
this.initTable();
}
/**
* Calcula la altura de la tabla.
*/
getTableHeight() {
const btHeight = window.innerHeight - this.$toolbar.height() - this.bottomMargin;
return btHeight < this.config.minHeight ? this.config.minHeight : btHeight;
}
/**
* Genera un ID único para la tabla basado en una cookie.
*/
getCookieId() {
const generateShortHash = (str) => {
let hash = 0;
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = (hash << 5) - hash + char;
hash &= hash; // Convertir a entero de 32 bits
}
return Math.abs(hash).toString().substring(0, 12);
};
return `bootstrap-table-cache-${generateShortHash(this.config.title)}`;
}
/**
* Carga los formatters dinámicamente
*/
async loadFormatters() {
const formattersModules = import.meta.glob('../../../../../**/resources/assets/js/bootstrap-table/*Formatters.js');
const formatterPromises = Object.entries(formattersModules).map(async ([path, importer]) => {
const module = await importer();
Object.assign(this.tableFormatters, module);
});
await Promise.all(formatterPromises);
}
btColumns() {
const columns = [];
Object.entries(this.config.header).forEach(([key, value]) => {
const columnFormat = this.config.format[key] || {};
if (typeof columnFormat.formatter === 'object') {
const formatterName = columnFormat.formatter.name;
const formatterParams = columnFormat.formatter.params || {};
const formatterFunction = this.tableFormatters[formatterName];
if (formatterFunction) {
columnFormat.formatter = (value, row, index) => formatterFunction(value, row, index, formatterParams);
} else {
console.warn(`Formatter "${formatterName}" no encontrado para la columna "${key}"`);
}
} else if (typeof columnFormat.formatter === 'string') {
const formatterFunction = this.tableFormatters[columnFormat.formatter];
if (formatterFunction) {
columnFormat.formatter = formatterFunction;
}
}
if (columnFormat.onlyFormatter) {
columns.push({
align: 'center',
formatter: columnFormat.formatter || (() => ''),
forceHide: true,
switchable: false,
field: key,
title: value,
});
return;
}
const column = {
title: value,
field: key,
sortable: true,
};
columns.push({ ...column, ...columnFormat });
});
return columns;
}
/**
* Petición AJAX para la tabla.
*/
ajaxRequest(params) {
const url = `${window.location.href}?${$.param(params.data)}&${$('.bt-toolbar :input').serialize()}`;
$.get(url).then((res) => params.success(res));
}
toValidFilename(str, extension = 'txt') {
return str
.normalize("NFD") // 🔹 Normaliza caracteres con tilde
.replace(/[\u0300-\u036f]/g, "") // 🔹 Elimina acentos y diacríticos
.replace(/[<>:"\/\\|?*\x00-\x1F]/g, '') // 🔹 Elimina caracteres inválidos
.replace(/\s+/g, '-') // 🔹 Reemplaza espacios con guiones
.replace(/-+/g, '-') // 🔹 Evita múltiples guiones seguidos
.replace(/^-+|-+$/g, '') // 🔹 Elimina guiones al inicio y fin
.toLowerCase() // 🔹 Convierte a minúsculas
+ (extension ? '.' + extension.replace(/^\.+/, '') : ''); // 🔹 Asegura la extensión válida
}
getFormattedDateYMDHm(date = new Date()) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0'); // 🔹 Asegura dos dígitos
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
return `${year}${month}${day}-${hours}${minutes}`;
}
/**
* Inicia la tabla después de cargar los formatters
*/
async initTable() {
await this.loadFormatters(); // Asegura que los formatters estén listos antes de inicializar
this.$bootstrapTable
.bootstrapTable('destroy').bootstrapTable({
height: this.config.height,
locale: 'es-MX',
ajax: (params) => this.ajaxRequest(params),
toolbar: this.config.toolbar,
search: this.config.search,
showColumns: this.config.showColumns,
showColumnsToggleAll: this.config.showColumnsToggleAll,
showExport: this.config.showExport,
exportTypes: ['csv', 'txt', 'xlsx'],
exportOptions: {
fileName: this.config.fileName,
},
showFullscreen: this.config.showFullscreen,
showPaginationSwitch: this.config.showPaginationSwitch,
showRefresh: this.config.showRefresh,
showToggle: this.config.showToggle,
clickToSelect: this.config.clickToSelect,
minimumCountColumns: this.config.minimumCountColumns,
fixedColumns: this.config.fixedColumns,
fixedNumber: this.config.fixedNumber,
idField: this.config.idField,
pagination: this.config.pagination,
pageList: this.config.pageList,
sidePagination: "server",
sortName: this.config.sortName,
sortOrder: this.config.sortOrder,
mobileResponsive: true,
resizable: true,
cookie: this.config.cookie,
cookieExpire: this.config.cookieExpire,
cookieIdTable: this.config.cookieIdTable,
columns: this.btColumns(),
});
}
}
window.BootstrapTableManager = BootstrapTableManager;

View File

@ -0,0 +1,132 @@
const appRoutesElement = document.getElementById('app-routes');
export const routes = appRoutesElement ? JSON.parse(appRoutesElement.textContent) : {};
export const booleanStatusCatalog = {
activo: {
trueText: 'Activo',
falseText: 'Inactivo',
trueClass: 'badge bg-label-success',
falseClass: 'badge bg-label-danger',
},
habilitado: {
trueText: 'Habilitado',
falseText: 'Deshabilitado',
trueClass: 'badge bg-label-success',
falseClass: 'badge bg-label-danger',
trueIcon: 'ti ti-checkup-list',
falseIcon: 'ti ti-ban',
},
checkSI: {
trueText: 'SI',
falseIcon: '',
trueClass: 'badge bg-label-info',
falseText: '',
},
check: {
trueIcon: 'ti ti-check',
falseIcon: '',
trueClass: 'text-green-800',
falseClass: '',
},
checkbox: {
trueIcon: 'ti ti-checkbox',
falseIcon: '',
trueClass: 'text-green-800',
falseClass: '',
},
checklist: {
trueIcon: 'ti ti-checklist',
falseIcon: '',
trueClass: 'text-green-800',
falseClass: '',
},
phone_done: {
trueIcon: 'ti ti-phone-done',
falseIcon: '',
trueClass: 'text-green-800',
falseClass: '',
},
checkup_list: {
trueIcon: 'ti ti-checkup-list',
falseIcon: '',
trueClass: 'text-green-800',
falseClass: '',
},
list_check: {
trueIcon: 'ti ti-list-check',
falseIcon: '',
trueClass: 'text-green-800',
falseClass: '',
},
camera_check: {
trueIcon: 'ti ti-camera-check',
falseIcon: '',
trueClass: 'text-green-800',
falseClass: '',
},
mail_check: {
trueIcon: 'ti ti-mail-check',
falseIcon: '',
trueClass: 'text-green-800',
falseClass: '',
},
clock_check: {
trueIcon: 'ti ti-clock-check',
falseIcon: '',
trueClass: 'text-green-800',
falseClass: '',
},
user_check: {
trueIcon: 'ti ti-user-check',
falseIcon: '',
trueClass: 'text-green-800',
falseClass: '',
},
circle_check: {
trueIcon: 'ti ti-circle-check',
falseIcon: '',
trueClass: 'text-green-800',
falseClass: '',
},
shield_check: {
trueIcon: 'ti ti-shield-check',
falseIcon: '',
trueClass: 'text-green-800',
falseClass: '',
},
calendar_check: {
trueIcon: 'ti ti-calendar-check',
falseIcon: '',
trueClass: 'text-green-800',
falseClass: '',
}
};
export const badgeColorCatalog = {
primary: { color: 'primary' },
secondary: { color: 'secondary' },
success: { color: 'success' },
danger: { color: 'danger' },
warning: { color: 'warning' },
info: { color: 'info' },
dark: { color: 'dark' },
light: { color: 'light', textColor: 'text-dark' }
};
export const statusIntBadgeBgCatalogCss = {
1: 'warning',
2: 'info',
10: 'success',
12: 'danger',
11: 'warning'
};
export const statusIntBadgeBgCatalog = {
1: 'Inactivo',
2: 'En proceso',
10: 'Activo',
11: 'Archivado',
12: 'Cancelado',
};

View File

@ -0,0 +1,193 @@
import { booleanStatusCatalog, statusIntBadgeBgCatalogCss, statusIntBadgeBgCatalog } from './globalConfig';
import {routes} from '../../../../../laravel-vuexy-admin/resources/assets/js/bootstrap-table/globalConfig.js';
export const userActionFormatter = (value, row, index) => {
if (!row.id) return '';
const showUrl = routes['admin.user.show'].replace(':id', row.id);
const editUrl = routes['admin.user.edit'].replace(':id', row.id);
const deleteUrl = routes['admin.user.delete'].replace(':id', row.id);
return `
<div class="flex space-x-2">
<a href="${editUrl}" title="Editar" class="icon-button hover:text-slate-700">
<i class="ti ti-edit"></i>
</a>
<a href="${deleteUrl}" title="Eliminar" class="icon-button hover:text-slate-700">
<i class="ti ti-trash"></i>
</a>
<a href="${showUrl}" title="Ver" class="icon-button hover:text-slate-700">
<i class="ti ti-eye"></i>
</a>
</div>
`.trim();
};
export const dynamicBooleanFormatter = (value, row, index, options = {}) => {
const { tag = 'default', customOptions = {} } = options;
const catalogConfig = booleanStatusCatalog[tag] || {};
const finalOptions = {
...catalogConfig,
...customOptions, // Permite sobreescribir la configuración predeterminada
...options // Permite pasar opciones rápidas
};
const {
trueIcon = '',
falseIcon = '',
trueText = 'Sí',
falseText = 'No',
trueClass = 'badge bg-label-success',
falseClass = 'badge bg-label-danger',
iconClass = 'text-green-800'
} = finalOptions;
const trueElement = !trueIcon && !trueText ? '' : `<span class="${trueClass}">${trueIcon ? `<i class="${trueIcon} ${iconClass}"></i> ` : ''}${trueText}</span>`;
const falseElement = !falseIcon && !falseText ? '' : `<span class="${falseClass}">${falseIcon ? `<i class="${falseIcon}"></i> ` : ''}${falseText}</span>`;
return value? trueElement : falseElement;
};
export const dynamicBadgeFormatter = (value, row, index, options = {}) => {
const {
color = 'primary', // Valor por defecto
textColor = '', // Permite agregar color de texto si es necesario
additionalClass = '' // Permite añadir clases adicionales
} = options;
return `<span class="badge bg-${color} ${textColor} ${additionalClass}">${value}</span>`;
};
export const statusIntBadgeBgFormatter = (value, row, index) => {
return value
? `<span class="badge bg-label-${statusIntBadgeBgCatalogCss[value]}">${statusIntBadgeBgCatalog[value]}</span>`
: '';
}
export const textNowrapFormatter = (value, row, index) => {
if (!value) return '';
return `<span class="text-nowrap">${value}</span>`;
}
export const toCurrencyFormatter = (value, row, index) => {
return isNaN(value) ? '' : Number(value).toCurrency();
}
export const numberFormatter = (value, row, index) => {
return isNaN(value) ? '' : Number(value);
}
export const monthFormatter = (value, row, index) => {
switch (parseInt(value)) {
case 1:
return 'Enero';
case 2:
return 'Febrero';
case 3:
return 'Marzo';
case 4:
return 'Abril';
case 5:
return 'Mayo';
case 6:
return 'Junio';
case 7:
return 'Julio';
case 8:
return 'Agosto';
case 9:
return 'Septiembre';
case 10:
return 'Octubre';
case 11:
return 'Noviembre';
case 12:
return 'Diciembre';
}
}
export const humaneTimeFormatter = (value, row, index) => {
return isNaN(value) ? '' : Number(value).humaneTime();
}
/**
* Genera la URL del avatar basado en iniciales o devuelve la foto de perfil si está disponible.
* @param {string} fullName - Nombre completo del usuario.
* @param {string|null} profilePhoto - Ruta de la foto de perfil.
* @returns {string} - URL del avatar.
*/
function getAvatarUrl(fullName, profilePhoto) {
const baseUrl = window.baseUrl || '';
if (profilePhoto) {
return `${baseUrl}storage/profile-photos/${profilePhoto}`;
}
return `${baseUrl}admin/usuario/avatar/?name=${fullName}`;
}
/**
* Formatea la columna del perfil de usuario con avatar, nombre y correo.
*/
export const userProfileFormatter = (value, row, index) => {
if (!row.id) return '';
const profileUrl = routes['admin.user.show'].replace(':id', row.id);
const avatar = getAvatarUrl(row.full_name, row.profile_photo_path);
const email = row.email ? row.email : 'Sin correo';
return `
<div class="flex items-center space-x-3" style="min-width: 240px">
<a href="${profileUrl}" class="flex-shrink-0">
<img src="${avatar}" alt="Avatar" class="w-10 h-10 rounded-full border border-gray-300 shadow-sm hover:scale-105 transition-transform">
</a>
<div class="truncate">
<a href="${profileUrl}" class="font-medium text-slate-700 hover:underline block text-wrap">${row.full_name}</a>
<small class="text-muted block truncate">${email}</small>
</div>
</div>
`;
};
/**
* Formatea la columna del perfil de contacto con avatar, nombre y correo.
*/
export const contactProfileFormatter = (value, row, index) => {
if (!row.id) return '';
const profileUrl = routes['admin.contact.show'].replace(':id', row.id);
const avatar = getAvatarUrl(row.full_name, row.profile_photo_path);
const email = row.email ? row.email : 'Sin correo';
return `
<div class="flex items-center space-x-3" style="min-width: 240px">
<a href="${profileUrl}" class="flex-shrink-0">
<img src="${avatar}" alt="Avatar" class="w-10 h-10 rounded-full border border-gray-300 shadow-sm hover:scale-105 transition-transform">
</a>
<div class="truncate">
<a href="${profileUrl}" class="font-medium text-slate-700 hover:underline block text-wrap">${row.full_name}</a>
<small class="text-muted block truncate">${email}</small>
</div>
</div>
`;
};
export const creatorFormatter = (value, row, index) => {
if (!row.creator) return '';
const email = row.creator_email || 'Sin correo';
const showUrl = routes['admin.user.show'].replace(':id', row.id);
return `
<div class="flex flex-col">
<a href="${showUrl}" class="font-medium text-slate-600 hover:underline block text-wrap">${row.creator}</a>
<small class="text-muted">${email}</small>
</div>
`;
};

View File

@ -0,0 +1,53 @@
/**
* Config
* -------------------------------------------------------------------------------------
* ! IMPORTANT: Make sure you clear the browser local storage In order to see the config changes in the template.
* ! To clear local storage: (https://www.leadshook.com/help/how-to-clear-local-storage-in-google-chrome-browser/).
*/
'use strict';
// JS global variables
window.config = {
colors: {
primary: '#7367f0',
secondary: '#808390',
success: '#28c76f',
info: '#00bad1',
warning: '#ff9f43',
danger: '#FF4C51',
dark: '#4b4b4b',
black: '#000',
white: '#fff',
cardColor: '#fff',
bodyBg: '#f8f7fa',
bodyColor: '#6d6b77',
headingColor: '#444050',
textMuted: '#acaab1',
borderColor: '#e6e6e8'
},
colors_label: {
primary: '#7367f029',
secondary: '#a8aaae29',
success: '#28c76f29',
info: '#00cfe829',
warning: '#ff9f4329',
danger: '#ea545529',
dark: '#4b4b4b29'
},
colors_dark: {
cardColor: '#2f3349',
bodyBg: '#25293c',
bodyColor: '#b2b1cb',
headingColor: '#cfcce4',
textMuted: '#8285a0',
borderColor: '#565b79'
},
enableMenuLocalStorage: true // Enable menu state with local storage support
};
window.assetsPath = document.documentElement.getAttribute('data-assets-path');
window.baseUrl = document.documentElement.getAttribute('data-base-url');
window.quicklinksUpdateUrl = document.documentElement.getAttribute('data-quicklinks-update-url');
window.templateName = document.documentElement.getAttribute('data-template');
window.rtlSupport = false; // set true for rtl support (rtl + ltr), false for ltr only.

View File

@ -0,0 +1,477 @@
/**
* FormCanvasHelper
*
* Clase para orquestar la interacción entre un formulario dentro de un Offcanvas
* de Bootstrap y el estado de Livewire (modo create/edit/delete), además de
* manipular ciertos componentes externos como Select2.
*
* Se diseñó teniendo en cuenta que el DOM del Offcanvas puede reconstruirse
* (re-render) de manera frecuente, por lo que muchos getters reacceden al DOM
* dinámicamente.
*/
export default class FormCanvasHelper {
/**
* @param {string} offcanvasId - ID del elemento Offcanvas en el DOM.
* @param {object} liveWireInstance - Instancia de Livewire asociada al formulario.
*/
constructor(offcanvasId, liveWireInstance) {
this.offcanvasId = offcanvasId;
this.liveWireInstance = liveWireInstance;
// Validamos referencias mínimas para evitar errores tempranos
// Si alguna falta, se mostrará un error en consola.
this.validateInitialDomRefs();
}
/**
* Verifica la existencia básica de elementos en el DOM.
* Muestra errores en consola si faltan elementos críticos.
*/
validateInitialDomRefs() {
const offcanvasEl = document.getElementById(this.offcanvasId);
if (!offcanvasEl) {
console.error(`❌ No se encontró el contenedor Offcanvas con ID: ${this.offcanvasId}`);
return;
}
const formEl = offcanvasEl.querySelector('form');
if (!formEl) {
console.error(`❌ No se encontró el formulario dentro de #${this.offcanvasId}`);
return;
}
const offcanvasTitle = offcanvasEl.querySelector('.offcanvas-title');
const submitButtons = formEl.querySelectorAll('.btn-submit');
const resetButtons = formEl.querySelectorAll('.btn-reset');
if (!offcanvasTitle || !submitButtons.length || !resetButtons.length) {
console.error(`❌ Faltan el título, botones de submit o reset dentro de #${this.offcanvasId}`);
}
}
/**
* Getter para el contenedor Offcanvas actual.
* Retorna siempre la referencia más reciente del DOM.
*/
get offcanvasEl() {
return document.getElementById(this.offcanvasId);
}
/**
* Getter para el formulario dentro del Offcanvas.
*/
get formEl() {
return this.offcanvasEl?.querySelector('form') ?? null;
}
/**
* Getter para el título del Offcanvas.
*/
get offcanvasTitleEl() {
return this.offcanvasEl?.querySelector('.offcanvas-title') ?? null;
}
/**
* Getter para la instancia de Bootstrap Offcanvas.
* Siempre retorna la instancia más reciente en caso de re-render.
*/
get offcanvasInstance() {
if (!this.offcanvasEl) return null;
return bootstrap.Offcanvas.getOrCreateInstance(this.offcanvasEl);
}
/**
* Retorna todos los botones de submit en el formulario.
*/
get submitButtons() {
return this.formEl?.querySelectorAll('.btn-submit') ?? [];
}
/**
* Retorna todos los botones de reset en el formulario.
*/
get resetButtons() {
return this.formEl?.querySelectorAll('.btn-reset') ?? [];
}
/**
* Método principal para manejar la recarga del Offcanvas según los estados en Livewire.
* Se encarga de resetear el formulario, limpiar errores y cerrar/abrir el Offcanvas
* según sea necesario.
*
* @param {string|null} triggerMode - Forzar la acción (e.g., 'reset', 'create'). Si no se especifica, se verifica según Livewire.
*/
reloadOffcanvas(triggerMode = null) {
setTimeout(() => {
const mode = this.liveWireInstance.get('mode');
const successProcess = this.liveWireInstance.get('successProcess');
const validationError = this.liveWireInstance.get('validationError');
// Si se completa la acción o triggerMode = 'reset',
// reseteamos completamente y cerramos el Offcanvas.
if (triggerMode === 'reset' || successProcess) {
this.resetFormAndState('create');
return;
}
// Forzar modo create si se solicita explícitamente
if (triggerMode === 'create') {
// Evitamos re-reset si ya estamos en 'create'
if (mode === 'create') return;
this.resetFormAndState('create');
this.focusOnOpen();
return;
}
// Si no, simplemente preparamos la UI según el modo actual.
this.prepareOffcanvasUI(mode);
// Si hay errores de validación, reabrimos el Offcanvas para mostrarlos.
if (validationError) {
this.liveWireInstance.set('validationError', null, false);
return;
}
// Si estamos en edit o delete, solo abrimos el Offcanvas.
if (mode === 'edit' || mode === 'delete') {
this.clearErrors();
if(mode === 'edit') {
this.focusOnOpen();
}
return;
}
}, 20);
}
/**
* Reabre o fuerza la apertura del Offcanvas si hay errores de validación
* o si el modo de Livewire es 'edit' o 'delete'.
*
* Normalmente se llama cuando hay un dispatch/evento de Livewire,
* por ejemplo si el servidor devuelve un error de validación (para mostrarlo)
* o si se acaba de cargar un registro para editar o eliminar.
*
* - Si hay `validationError`, forzamos la reapertura con `toggleOffcanvas(true, true)`
* para que se refresque correctamente y el usuario vea los errores.
* - Si el modo es 'edit' o 'delete', simplemente mostramos el Offcanvas sin forzar
* un refresco de la interfaz.
*/
refresh() {
setTimeout(() => {
const mode = this.liveWireInstance.get('mode');
const successProcess = this.liveWireInstance.get('successProcess');
const validationError = this.liveWireInstance.get('validationError');
// cerramos el Offcanvas.
if (successProcess) {
this.toggleOffcanvas(false);
this.resetFormAndState('create');
return;
}
if (validationError) {
// Forzamos la reapertura para que se rendericen
this.toggleOffcanvas(true, true);
return;
}
if (mode === 'edit' || mode === 'delete') {
// Abrimos el Offcanvas para edición o eliminación
this.toggleOffcanvas(true);
return;
}
}, 10);
}
/**
* Prepara la UI del Offcanvas según el modo actual: cambia texto de botones, título,
* habilita o deshabilita campos, etc.
*
* @param {string} mode - Modo actual en Livewire: 'create', 'edit' o 'delete'
*/
prepareOffcanvasUI(mode) {
// Configura el texto y estilo de botones
this.configureButtons(mode);
// Ajusta el título del Offcanvas
this.configureTitle(mode);
// Activa o desactiva campos según el modo
this.configureReadonlyMode(mode === 'delete');
}
/**
* Cierra o muestra el Offcanvas.
*
* @param {boolean} show - true para mostrar, false para ocultar.
* @param {boolean} force - true para forzar el refresco rápido del Offcanvas.
*/
toggleOffcanvas(show = false, force = false) {
const instance = this.offcanvasInstance;
if (!instance) return;
if (show) {
if (force) {
// "Force" hace un hide + show para asegurar un nuevo render
instance.hide();
setTimeout(() => instance.show(), 10);
} else {
instance.show();
}
} else {
instance.hide();
}
}
/**
* Resetea el formulario y el estado en Livewire (modo, id, errores).
*
* @param {string} targetMode - Modo al que queremos resetear, típicamente 'create'.
*/
resetFormAndState(targetMode) {
if (!this.formEl) return;
// Restablecemos en Livewire
this.liveWireInstance.set('successProcess', null, false);
this.liveWireInstance.set('validationError', null, false);
this.liveWireInstance.set('mode', targetMode, false);
this.liveWireInstance.set('id', null, false);
// Limpiamos el formulario
this.formEl.reset();
this.clearErrors();
// Restablecemos valores por defecto del formulario
const defaults = this.liveWireInstance.get('defaultValues');
if (defaults && typeof defaults === 'object') {
Object.entries(defaults).forEach(([key, value]) => {
this.liveWireInstance.set(key, value, false);
});
}
// Limpiar select2 automáticamente
$(this.formEl)
.find('select.select2-hidden-accessible')
.each(function () {
$(this).val(null).trigger('change');
});
// Desactivamos el modo lectura
this.configureReadonlyMode(false);
// Reconfiguramos el Offcanvas UI
this.prepareOffcanvasUI(targetMode);
}
/**
* Configura el texto y estilo de los botones de submit y reset
* según el modo de Livewire.
*
* @param {string} mode - 'create', 'edit' o 'delete'
*/
configureButtons(mode) {
const singularName = this.liveWireInstance.get('singularName');
// Limpiar clases previas
this.submitButtons.forEach(button => {
button.classList.remove('btn-danger', 'btn-primary');
});
this.resetButtons.forEach(button => {
button.classList.remove('btn-text-secondary', 'btn-label-secondary');
});
// Configurar botón de submit según el modo
this.submitButtons.forEach(button => {
switch (mode) {
case 'create':
button.classList.add('btn-primary');
button.textContent = `Crear ${singularName.toLowerCase()}`;
break;
case 'edit':
button.classList.add('btn-primary');
button.textContent = `Guardar cambios`;
break;
case 'delete':
button.classList.add('btn-danger');
button.textContent = `Eliminar ${singularName.toLowerCase()}`;
break;
}
});
// Configurar botones de reset según el modo
this.resetButtons.forEach(button => {
// Cambia la clase dependiendo si se trata de un modo 'delete' o no
const buttonClass = (mode === 'delete') ? 'btn-text-secondary' : 'btn-label-secondary';
button.classList.add(buttonClass);
});
}
/**
* Ajusta el título del Offcanvas según el modo y la propiedad configurada en Livewire.
*
* @param {string} mode - 'create', 'edit' o 'delete'
*/
configureTitle(mode) {
if (!this.offcanvasTitleEl) return;
const capitalizeFirstLetter =(str) => {
return str.charAt(0).toUpperCase() + str.slice(1);
}
const singularName = this.liveWireInstance.get('singularName');
const columnNameLabel = this.liveWireInstance.get('columnNameLabel');
const editName = this.liveWireInstance.get(columnNameLabel);
switch (mode) {
case 'create':
this.offcanvasTitleEl.innerHTML = `<i class="ti ti-plus ml-2"></i> ${capitalizeFirstLetter(singularName)} `;
break;
case 'edit':
this.offcanvasTitleEl.innerHTML = `${editName} <i class="ti ti-lg ti-pencil ml-2 text-success"></i>`;
break;
case 'delete':
this.offcanvasTitleEl.innerHTML = `${editName} <i class="ti ti-lg ti-eraser ml-2 text-danger"></i>`;
break;
}
}
/**
* Configura el modo de solo lectura/edición en los campos del formulario.
* Deshabilita inputs y maneja el "readonly" en checkboxes/radios.
*
* @param {boolean} readOnly - true si queremos modo lectura, false para edición.
*/
configureReadonlyMode(readOnly) {
if (!this.formEl) return;
const inputs = this.formEl.querySelectorAll('input, textarea, select');
inputs.forEach(el => {
// Saltar campos marcados como "data-always-enabled"
if (el.hasAttribute('data-always-enabled')) return;
// Para selects
if (el.tagName === 'SELECT') {
if ($(el).hasClass('select2-hidden-accessible')) {
// Deshabilitar select2
$(el).prop('disabled', readOnly).trigger('change.select2');
} else {
this.toggleSelectReadonly(el, readOnly);
}
return;
}
// Para checkboxes / radios
if (el.type === 'checkbox' || el.type === 'radio') {
this.toggleCheckboxReadonly(el, readOnly);
return;
}
// Para inputs de texto / textarea
el.readOnly = readOnly;
});
}
/**
* Alterna modo "readonly" en un checkbox/radio simulando la inhabilitación
* sin marcarlo como 'disabled' (para mantener su apariencia).
*
* @param {HTMLElement} checkbox - Elemento checkbox o radio.
* @param {boolean} enabled - true si se quiere modo lectura, false en caso contrario.
*/
toggleCheckboxReadonly(checkbox, enabled) {
if (enabled) {
checkbox.setAttribute('readonly-mode', 'true');
checkbox.style.pointerEvents = 'none';
checkbox.onclick = function (event) {
event.preventDefault();
};
} else {
checkbox.removeAttribute('readonly-mode');
checkbox.style.pointerEvents = '';
checkbox.onclick = null;
}
}
/**
* Alterna modo "readonly" para un <select> convencional.
*
* @param {HTMLElement} select - Elemento select.
* @param {boolean} enabled - true si queremos readonly, false si editable.
*/
toggleSelectReadonly(select, enabled) {
if (enabled) {
select.setAttribute('readonly-mode', 'true');
select.style.pointerEvents = 'none';
select.tabIndex = -1;
} else {
select.removeAttribute('readonly-mode');
select.style.pointerEvents = '';
select.tabIndex = '';
}
}
/**
* Hace focus en el elemento con el selector dado.
*/
focusOnOpen() {
const focusSelector = this.liveWireInstance.get('focusOnOpen'); // Obtiene el selector de Livewire
if (!focusSelector) return;
setTimeout(() => {
// Buscar el elemento real en el DOM
const focusElement = document.getElementById(focusSelector);
// Si existe, hacer focus
if (focusElement) {
focusElement.focus();
} else {
console.warn(`Elemento no encontrado: ${focusSelector}`);
}
}, 250);
}
/**
* Limpia mensajes de error y la clase 'is-invalid' en el formulario.
*/
clearErrors() {
if (!this.formEl) return;
// Remover mensajes de error en texto
this.formEl.querySelectorAll('.text-danger').forEach(el => el.remove());
// Remover la clase 'is-invalid' de los inputs afectados
this.formEl.querySelectorAll('.is-invalid').forEach(el => el.classList.remove('is-invalid'));
// Remover las notificaciones
this.formEl.querySelectorAll('.notification-container').forEach(el => el.innerHTML = '');
// Removemos el checkbox de confirmación de eliminar
const confirmDeletion = this.formEl.querySelector('.confirm-deletion');
if (confirmDeletion) {
confirmDeletion.remove();
}
}
}
// Exponemos la clase en window para acceso global (si fuese necesario)
window.FormCanvasHelper = FormCanvasHelper;

View File

@ -0,0 +1,245 @@
export default class FormCustomListener {
constructor(config = {}) {
const defaultConfig = {
formSelector: '.form-custom-listener', // Selector para formularios
buttonSelectors: [], // Selectores específicos para botones
callbacks: [], // Callbacks correspondientes a los botones específicos
allowedInputTags: ['INPUT', 'SELECT', 'TEXTAREA'], // Tags permitidos para cambios
validationConfig: null, // Nueva propiedad para la configuración de validación
dispatchOnSubmit: null // Callback Livewire para disparar al enviar el formulario
};
this.config = { ...defaultConfig, ...config };
// Aseguramos que los métodos que dependen de `this` estén vinculados al contexto correcto
this.defaultButtonHandler = this.defaultButtonHandler.bind(this);
this.formValidationInstance = null;
this.initForms();
}
/**
* Inicializa los formularios encontrados en el DOM.
*/
initForms() {
const forms = document.querySelectorAll(this.config.formSelector);
if (forms.length === 0) {
console.error(`No se encontraron formularios con el selector ${this.config.formSelector}.`);
return;
}
forms.forEach(form => {
if (form.dataset.initialized === 'true') {
console.warn(`Formulario ya inicializado: ${form}`);
return;
}
this.initFormEvents(form);
// Si se pasó configuración de validación, inicialízala
if (this.config.validationConfig) {
this.initializeValidation(form);
}
form.dataset.initialized = 'true'; // Marcar formulario como inicializado
});
}
/**
* Configura los eventos para un formulario individual.
* @param {HTMLElement} form - El formulario que será manejado.
*/
initFormEvents(form) {
const buttons = this.getButtons(form);
buttons.forEach(({ button, callback }, index) => {
if (button) {
button.addEventListener('click', () => {
this.handleButtonClick(index, form, buttons, callback);
});
}
});
form.addEventListener('input', event =>
this.handleInputChange(
event,
form,
buttons.map(b => b.button)
)
);
}
/**
* Obtiene los botones y sus callbacks según la configuración.
* @param {HTMLElement} form - El formulario del cual obtener botones.
* @returns {Array} Array de objetos con { button, callback }.
*/
getButtons(form) {
const buttons = [];
this.config.buttonSelectors.forEach((selector, index) => {
const buttonList = Array.from(form.querySelectorAll(selector));
const callback = this.config.callbacks[index];
buttonList.forEach(button => {
buttons.push({ button, callback });
});
});
return buttons;
}
/**
* Maneja los cambios en los campos de entrada.
* @param {Event} event - El evento del cambio.
* @param {HTMLElement} form - El formulario actual.
* @param {HTMLElement[]} buttons - Array de botones en el formulario.
*/
handleInputChange(event, form, buttons) {
const target = event.target;
if (['INPUT', 'SELECT', 'TEXTAREA'].includes(target.tagName)) {
this.toggleButtonsState(buttons, true);
}
}
/**
* Maneja el clic en un botón específico.
* @param {number} index - Índice del botón.
* @param {HTMLElement} form - El formulario actual.
* @param {Array} buttons - Array de objetos { button, callback }.
* @param {function|null} callback - Callback definido para el botón.
*/
handleButtonClick(index, form, buttons, callback) {
if (typeof callback === 'function') {
callback(
form,
buttons[index].button,
buttons.map(b => b.button)
);
} else {
this.defaultButtonHandler(
form,
buttons[index].button,
buttons.map(b => b.button)
);
}
}
/**
* Maneja la acción cuando el formulario es válido.
* Este método puede ser sobreescrito para personalizar el comportamiento.
*/
handleFormValid(form) {
// Ejecutar callback opcional (si lo proporcionaste)
if (typeof this.config.handleValidForm === 'function') {
this.config.handleValidForm(form);
} else if (this.config.dispatchOnSubmit) {
this.handleValidForm(form);
} else {
form.submit();
}
}
/**
* Método que maneja la acción cuando el formulario es válido.
* Al ser un método de la clase, no necesitamos usar bind.
*/
handleValidForm(form) {
const saveButton = form.querySelector('#save_website_button');
const allButtons = Array.from(form.querySelectorAll('.btn'));
this.toggleButtonsState(allButtons, false); // Deshabilitar todos los botones
this.toggleFormFields(form, false); // Deshabilitar todos los campos del formulario
this.setButtonLoadingState(saveButton, true); // Poner en estado de carga al botón anfitrión
// Enviar la solicitud de Livewire correspondiente al enviar el formulario
Livewire.dispatch(this.config.dispatchOnSubmit);
}
/**
* Manejador por defecto para los botones.
* @param {HTMLElement} form - El formulario actual.
* @param {HTMLElement} hostButton - El botón anfitrión que disparó el evento.
* @param {HTMLElement[]} allButtons - Todos los botones relevantes del formulario.
*/
defaultButtonHandler(form, hostButton, allButtons) {
this.toggleButtonsState(allButtons, false); // Deshabilitar todos los botones
this.toggleFormFields(form, false); // Deshabilitar todos los campos del formulario
this.setButtonLoadingState(hostButton, true); // Poner en estado de carga al botón anfitrión
}
/**
* Deshabilita o habilita los campos del formulario.
* @param {HTMLElement} form - El formulario actual.
* @param {boolean} isEnabled - Si los campos deben habilitarse.
*/
toggleFormFields(form, isEnabled) {
form.querySelectorAll('input, select, textarea').forEach(field => {
field.disabled = !isEnabled;
});
}
/**
* Habilita o deshabilita los botones.
* @param {HTMLElement[]} buttons - Array de botones.
* @param {boolean} isEnabled - Si los botones deben habilitarse.
*/
toggleButtonsState(buttons, isEnabled) {
buttons.forEach(button => {
if (button) button.disabled = !isEnabled;
});
}
/**
* Cambia el estado de carga de un botón.
* @param {HTMLElement} button - Botón que se manejará.
* @param {boolean} isLoading - Si el botón está en estado de carga.
*/
setButtonLoadingState(button, isLoading) {
if (!button) return;
const loadingText = button.getAttribute('data-loading-text');
if (loadingText && isLoading) {
button.setAttribute('data-original-text', button.innerHTML);
button.innerHTML = loadingText;
button.disabled = true;
} else if (!isLoading) {
button.innerHTML = button.getAttribute('data-original-text') || button.innerHTML;
button.disabled = false;
}
}
/**
* Inicializa la validación del formulario con la configuración proporcionada.
* @param {HTMLElement} form - El formulario que va a ser validado.
*/
initializeValidation(form) {
if (this.config.validationConfig) {
this.formValidationInstance = FormValidation.formValidation(form, this.config.validationConfig).on(
'core.form.valid',
() => this.handleFormValid(form)
);
}
}
reloadValidation() {
const form = document.querySelector(this.config.formSelector);
// Verificar si el formulario existe y si la validación está inicializada
if (form && this.formValidationInstance) {
try {
// En lugar de destruir la validación, simplemente reiniciamos la validación.
this.formValidationInstance.resetForm(); // Resetear el formulario, limpiando los errores
// Reinicializar la validación con la configuración actual
this.initializeValidation(form);
} catch (error) {
console.error('Error al reiniciar la validación:', error);
}
} else {
console.warn('Formulario no encontrado o instancia de validación no disponible.');
}
}
}

View File

@ -0,0 +1,56 @@
/**
* Quicklinks Navbar
*/
'use strict';
$(function () {
// Navbar Quicklinks with autosuggest (typeahead)
const $dropdownShortcuts = $('.dropdown-shortcuts'),
$dropdownShortcutsAdd = $('.dropdown-shortcuts-add'),
$dropdownShortcutsRemove = $('.dropdown-shortcuts-remove');
const route = document.documentElement.getAttribute('data-route');
if ($dropdownShortcuts.length) {
$dropdownShortcutsAdd.on('click', function () {
$.ajax({
url: quicklinksUpdateUrl,
method: 'POST',
data: {
action: 'update',
route: route
},
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
success: function (response) {
location.reload();
},
error: function (xhr) {
console.error(xhr.responseJSON.message);
}
});
});
$dropdownShortcutsRemove.on('click', function () {
$.ajax({
url: quicklinksUpdateUrl,
method: 'POST',
data: {
action: 'remove',
route: route
},
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
success: function (response) {
location.reload();
},
error: function (xhr) {
console.error(xhr.responseJSON.message);
}
});
});
}
});

View File

@ -0,0 +1,201 @@
/**
* Search Navbar
*/
'use strict';
$(function () {
window.Helpers.initSidebarToggle();
// Toggle Universal Sidebar
// Navbar Search with autosuggest (typeahead)
var searchToggler = $('.search-toggler'),
searchInputWrapper = $('.search-input-wrapper'),
searchInput = $('.search-input'),
contentBackdrop = $('.content-backdrop');
// Open search input on click of search icon
if (searchToggler.length) {
searchToggler.on('click', function () {
if (searchInputWrapper.length) {
searchInputWrapper.toggleClass('d-none');
searchInput.trigger('focus');
}
});
document.addEventListener('keydown', function (event) {
const ctrlKey = event.ctrlKey;
const slashKey = event.key === '/'; // Usa 'key' para obtener la tecla como texto
if (ctrlKey && slashKey) {
const searchInputWrapper = document.querySelector('.search-input-wrapper');
const searchInput = document.querySelector('.search-input');
if (searchInputWrapper) {
searchInputWrapper.classList.toggle('d-none'); // Alterna la visibilidad
if (searchInput) {
searchInput.focus(); // Coloca el foco en el input
}
}
}
});
// Note: Following code is required to update container class of typeahead dropdown width on focus of search input. setTimeout is required to allow time to initiate Typeahead UI.
setTimeout(function () {
var twitterTypeahead = $('.twitter-typeahead');
searchInput.on('focus', function () {
if (searchInputWrapper.hasClass('container-xxl')) {
searchInputWrapper.find(twitterTypeahead).addClass('container-xxl');
twitterTypeahead.removeClass('container-fluid');
} else if (searchInputWrapper.hasClass('container-fluid')) {
searchInputWrapper.find(twitterTypeahead).addClass('container-fluid');
twitterTypeahead.removeClass('container-xxl');
}
});
}, 10);
}
if (searchInput.length) {
// Función para normalizar cadenas (eliminar acentos)
function normalizeString(str) {
return str
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
.toLowerCase();
}
// Filter config con soporte para ignorar acentos
var filterConfig = function (data) {
return function findMatches(q, cb) {
let matches = [];
// Normalizar la consulta
const normalizedQuery = normalizeString(q);
data.filter(function (i) {
const normalizedName = normalizeString(i.name);
if (normalizedName.startsWith(normalizedQuery)) {
matches.push(i);
} else if (
!normalizedName.startsWith(normalizedQuery) &&
normalizedName.includes(normalizedQuery)
) {
matches.push(i);
// Ordenar por coincidencia secundaria
matches.sort(function (a, b) {
return b.name < a.name ? 1 : -1;
});
}
});
cb(matches);
};
};
// Search JSON
var searchJson = 'search-navbar'; // For vertical layout
if ($('#layout-menu').hasClass('menu-horizontal')) {
var searchJson = 'search-navbar'; // For vertical layout
}
// Search API AJAX call
var searchData = $.ajax({
url: assetsPath + '../../admin/' + searchJson, //? Use your own search api instead
dataType: 'json',
async: false
}).responseJSON;
// Init typeahead on searchInput
searchInput.each(function () {
var $this = $(this);
searchInput
.typeahead(
{
hint: false,
classNames: {
menu: 'tt-menu navbar-search-suggestion',
cursor: 'active',
suggestion: 'suggestion d-flex justify-content-between px-4 py-2 w-100'
}
},
// Páginas
{
name: 'pages',
display: 'name',
limit: 8,
source: filterConfig(searchData.pages),
templates: {
header: '<h6 class="suggestions-header text-primary mb-0 mx-4 mt-3 pb-2">Páginas</h6>',
suggestion: function ({ url, icon, name }) {
return (
'<a href="' +
url +
'">' +
'<div>' +
'<i class="ti ' +
icon +
' me-2"></i>' +
'<span class="align-middle">' +
name +
'</span>' +
'</div>' +
'</a>'
);
},
notFound:
'<div class="not-found px-4 py-2">' +
'<h6 class="suggestions-header text-primary mb-2">Páginas</h6>' +
'<p class="py-2 mb-0"><i class="ti ti-alert-circle ti-xs me-2"></i> No se encontro resultados</p>' +
'</div>'
}
}
)
//On typeahead result render.
.on('typeahead:render', function () {
// Show content backdrop,
contentBackdrop.addClass('show').removeClass('fade');
})
// On typeahead select
.on('typeahead:select', function (ev, suggestion) {
// Open selected page
if (suggestion.url !== 'javascript:;') window.location = suggestion.url;
})
// On typeahead close
.on('typeahead:close', function () {
// Clear search
searchInput.val('');
$this.typeahead('val', '');
// Hide search input wrapper
searchInputWrapper.addClass('d-none');
// Fade content backdrop
contentBackdrop.addClass('fade').removeClass('show');
});
// On searchInput keyup, Fade content backdrop if search input is blank
searchInput.on('keyup', function () {
if (searchInput.val() == '') contentBackdrop.addClass('fade').removeClass('show');
});
});
// Init PerfectScrollbar in search result
var psSearch;
$('.navbar-search-suggestion').each(function () {
psSearch = new PerfectScrollbar($(this)[0], {
wheelPropagation: false,
suppressScrollX: true
});
});
searchInput.on('keyup', function () {
psSearch.update();
});
}
});

375
resources/assets/js/main.js Normal file
View File

@ -0,0 +1,375 @@
import './layout/quicklinks-navbar.js';
import './layout/search-navbar.js';
('use strict');
window.isRtl = window.Helpers.isRtl();
window.isDarkStyle = window.Helpers.isDarkStyle();
let menu,
animate,
isHorizontalLayout = false;
if (document.getElementById('layout-menu')) {
isHorizontalLayout = document.getElementById('layout-menu').classList.contains('menu-horizontal');
}
(function () {
setTimeout(function () {
window.Helpers.initCustomOptionCheck();
}, 1000);
if (typeof Waves !== 'undefined') {
Waves.init();
Waves.attach(
".btn[class*='btn-']:not(.position-relative):not([class*='btn-outline-']):not([class*='btn-label-'])",
['waves-light']
);
Waves.attach("[class*='btn-outline-']:not(.position-relative)");
Waves.attach("[class*='btn-label-']:not(.position-relative)");
Waves.attach('.pagination .page-item .page-link');
Waves.attach('.dropdown-menu .dropdown-item');
Waves.attach('.light-style .list-group .list-group-item-action');
Waves.attach('.dark-style .list-group .list-group-item-action', ['waves-light']);
Waves.attach('.nav-tabs:not(.nav-tabs-widget) .nav-item .nav-link');
Waves.attach('.nav-pills .nav-item .nav-link', ['waves-light']);
}
// Initialize menu
//-----------------
let layoutMenuEl = document.querySelectorAll('#layout-menu');
layoutMenuEl.forEach(function (element) {
menu = new Menu(element, {
orientation: isHorizontalLayout ? 'horizontal' : 'vertical',
closeChildren: isHorizontalLayout ? true : false,
// ? This option only works with Horizontal menu
showDropdownOnHover: localStorage.getItem('templateCustomizer-' + templateName + '--ShowDropdownOnHover') // If value(showDropdownOnHover) is set in local storage
? localStorage.getItem('templateCustomizer-' + templateName + '--ShowDropdownOnHover') === 'true' // Use the local storage value
: window.templateCustomizer !== undefined // If value is set in config.js
? window.templateCustomizer.settings.defaultShowDropdownOnHover // Use the config.js value
: true // Use this if you are not using the config.js and want to set value directly from here
});
// Change parameter to true if you want scroll animation
window.Helpers.scrollToActive((animate = false));
window.Helpers.mainMenu = menu;
});
// Initialize menu togglers and bind click on each
let menuToggler = document.querySelectorAll('.layout-menu-toggle');
menuToggler.forEach(item => {
item.addEventListener('click', event => {
event.preventDefault();
window.Helpers.toggleCollapsed();
// Enable menu state with local storage support if enableMenuLocalStorage = true from config.js
if (config.enableMenuLocalStorage && !window.Helpers.isSmallScreen()) {
try {
localStorage.setItem(
'templateCustomizer-' + templateName + '--LayoutCollapsed',
String(window.Helpers.isCollapsed())
);
// Update customizer checkbox state on click of menu toggler
let layoutCollapsedCustomizerOptions = document.querySelector(
'.template-customizer-layouts-options'
);
if (layoutCollapsedCustomizerOptions) {
let layoutCollapsedVal = window.Helpers.isCollapsed() ? 'collapsed' : 'expanded';
layoutCollapsedCustomizerOptions.querySelector(`input[value="${layoutCollapsedVal}"]`).click();
}
} catch (e) {}
}
});
});
// Menu swipe gesture
// Detect swipe gesture on the target element and call swipe In
window.Helpers.swipeIn('.drag-target', function (e) {
window.Helpers.setCollapsed(false);
});
// Detect swipe gesture on the target element and call swipe Out
window.Helpers.swipeOut('#layout-menu', function (e) {
if (window.Helpers.isSmallScreen()) window.Helpers.setCollapsed(true);
});
// Display in main menu when menu scrolls
let menuInnerContainer = document.getElementsByClassName('menu-inner'),
menuInnerShadow = document.getElementsByClassName('menu-inner-shadow')[0];
if (menuInnerContainer.length > 0 && menuInnerShadow) {
menuInnerContainer[0].addEventListener('ps-scroll-y', function () {
if (this.querySelector('.ps__thumb-y').offsetTop) {
menuInnerShadow.style.display = 'block';
} else {
menuInnerShadow.style.display = 'none';
}
});
}
// Update light/dark image based on current style
function switchImage(style) {
if (style === 'system') {
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
style = 'dark';
} else {
style = 'light';
}
}
const switchImagesList = [].slice.call(document.querySelectorAll('[data-app-' + style + '-img]'));
switchImagesList.map(function (imageEl) {
const setImage = imageEl.getAttribute('data-app-' + style + '-img');
imageEl.src = baseUrl + 'vendor/vuexy-admin/img/' + setImage; // Using window.assetsPath to get the exact relative path
});
}
//Style Switcher (Light/Dark/System Mode)
let styleSwitcher = document.querySelector('.dropdown-style-switcher');
// Active class on style switcher dropdown items
const activeStyle = document.documentElement.getAttribute('data-style');
// Get style from local storage or use 'system' as default
let storedStyle =
localStorage.getItem('templateCustomizer-' + templateName + '--Style') || //if no template style then use Customizer style
(window.templateCustomizer?.settings?.defaultStyle ?? 'light'); //!if there is no Customizer then use default style as light
// Set style on click of style switcher item if template customizer is enabled
if (window.templateCustomizer && styleSwitcher) {
let styleSwitcherItems = [].slice.call(styleSwitcher.children[1].querySelectorAll('.dropdown-item'));
styleSwitcherItems.forEach(function (item) {
item.classList.remove('active');
item.addEventListener('click', function () {
let currentStyle = this.getAttribute('data-theme');
if (currentStyle === 'light') {
window.templateCustomizer.setStyle('light');
} else if (currentStyle === 'dark') {
window.templateCustomizer.setStyle('dark');
} else {
window.templateCustomizer.setStyle('system');
}
});
if (item.getAttribute('data-theme') === activeStyle) {
// Add 'active' class to the item if it matches the activeStyle
item.classList.add('active');
}
});
// Update style switcher icon based on the stored style
const styleSwitcherIcon = styleSwitcher.querySelector('i');
if (storedStyle === 'light') {
styleSwitcherIcon.classList.add('ti-sun');
new bootstrap.Tooltip(styleSwitcherIcon, {
title: 'Light Mode',
fallbackPlacements: ['bottom']
});
} else if (storedStyle === 'dark') {
styleSwitcherIcon.classList.add('ti-moon-stars');
new bootstrap.Tooltip(styleSwitcherIcon, {
title: 'Dark Mode',
fallbackPlacements: ['bottom']
});
} else {
styleSwitcherIcon.classList.add('ti-device-desktop-analytics');
new bootstrap.Tooltip(styleSwitcherIcon, {
title: 'System Mode',
fallbackPlacements: ['bottom']
});
}
}
// Run switchImage function based on the stored style
switchImage(storedStyle);
let languageDropdown = document.getElementsByClassName('dropdown-language');
if (languageDropdown.length) {
let dropdownItems = languageDropdown[0].querySelectorAll('.dropdown-item');
const dropdownActiveItem = languageDropdown[0].querySelector('.dropdown-item.active');
directionChange(dropdownActiveItem.dataset.textDirection);
for (let i = 0; i < dropdownItems.length; i++) {
dropdownItems[i].addEventListener('click', function () {
let textDirection = this.getAttribute('data-text-direction');
window.templateCustomizer.setLang(this.getAttribute('data-language'));
directionChange(textDirection);
});
}
function directionChange(textDirection) {
if (textDirection === 'rtl') {
if (localStorage.getItem('templateCustomizer-' + templateName + '--Rtl') !== 'true')
window.templateCustomizer ? window.templateCustomizer.setRtl(true) : '';
} else {
if (localStorage.getItem('templateCustomizer-' + templateName + '--Rtl') === 'true')
window.templateCustomizer ? window.templateCustomizer.setRtl(false) : '';
}
}
}
// add on click javascript for template customizer reset button id template-customizer-reset-btn
setTimeout(function () {
let templateCustomizerResetBtn = document.querySelector('.template-customizer-reset-btn');
if (templateCustomizerResetBtn) {
templateCustomizerResetBtn.onclick = function () {
window.location.href = baseUrl + 'lang/en';
};
}
}, 1500);
// Notification
// ------------
const notificationMarkAsReadAll = document.querySelector('.dropdown-notifications-all');
const notificationMarkAsReadList = document.querySelectorAll('.dropdown-notifications-read');
// Notification: Mark as all as read
if (notificationMarkAsReadAll) {
notificationMarkAsReadAll.addEventListener('click', event => {
notificationMarkAsReadList.forEach(item => {
item.closest('.dropdown-notifications-item').classList.add('marked-as-read');
});
});
}
// Notification: Mark as read/unread onclick of dot
if (notificationMarkAsReadList) {
notificationMarkAsReadList.forEach(item => {
item.addEventListener('click', event => {
item.closest('.dropdown-notifications-item').classList.toggle('marked-as-read');
});
});
}
// Notification: Mark as read/unread onclick of dot
const notificationArchiveMessageList = document.querySelectorAll('.dropdown-notifications-archive');
notificationArchiveMessageList.forEach(item => {
item.addEventListener('click', event => {
item.closest('.dropdown-notifications-item').remove();
});
});
// Init helpers & misc
// --------------------
// Init BS Tooltip
const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl);
});
// Accordion active class
const accordionActiveFunction = function (e) {
if (e.type == 'show.bs.collapse' || e.type == 'show.bs.collapse') {
e.target.closest('.accordion-item').classList.add('active');
} else {
e.target.closest('.accordion-item').classList.remove('active');
}
};
const accordionTriggerList = [].slice.call(document.querySelectorAll('.accordion'));
const accordionList = accordionTriggerList.map(function (accordionTriggerEl) {
accordionTriggerEl.addEventListener('show.bs.collapse', accordionActiveFunction);
accordionTriggerEl.addEventListener('hide.bs.collapse', accordionActiveFunction);
});
// If layout is RTL add .dropdown-menu-end class to .dropdown-menu
// if (isRtl) {
// Helpers._addClass('dropdown-menu-end', document.querySelectorAll('#layout-navbar .dropdown-menu'));
// }
// Auto update layout based on screen size
window.Helpers.setAutoUpdate(true);
// Toggle Password Visibility
window.Helpers.initPasswordToggle();
// Speech To Text
window.Helpers.initSpeechToText();
// Init PerfectScrollbar in Navbar Dropdown (i.e notification)
window.Helpers.initNavbarDropdownScrollbar();
let horizontalMenuTemplate = document.querySelector("[data-template^='horizontal-menu']");
if (horizontalMenuTemplate) {
// if screen size is small then set navbar fixed
if (window.innerWidth < window.Helpers.LAYOUT_BREAKPOINT) {
window.Helpers.setNavbarFixed('fixed');
} else {
window.Helpers.setNavbarFixed('');
}
}
// On window resize listener
// -------------------------
document.addEventListener(
'resize',
function (event) {
// Hide open search input and set value blank
if (window.innerWidth >= window.Helpers.LAYOUT_BREAKPOINT) {
if (document.querySelector('.search-input-wrapper')) {
document.querySelector('.search-input-wrapper').classList.add('d-none');
document.querySelector('.search-input').value = '';
}
}
// Horizontal Layout : Update menu based on window size
if (horizontalMenuTemplate) {
// if screen size is small then set navbar fixed
if (window.innerWidth < window.Helpers.LAYOUT_BREAKPOINT) {
window.Helpers.setNavbarFixed('fixed');
} else {
window.Helpers.setNavbarFixed('');
}
setTimeout(function () {
if (window.innerWidth < window.Helpers.LAYOUT_BREAKPOINT) {
if (document.getElementById('layout-menu')) {
if (document.getElementById('layout-menu').classList.contains('menu-horizontal')) {
menu.switchMenu('vertical');
}
}
} else {
if (document.getElementById('layout-menu')) {
if (document.getElementById('layout-menu').classList.contains('menu-vertical')) {
menu.switchMenu('horizontal');
}
}
}
}, 100);
}
},
true
);
// Manage menu expanded/collapsed with templateCustomizer & local storage
//------------------------------------------------------------------
// If current layout is horizontal OR current window screen is small (overlay menu) than return from here
if (isHorizontalLayout || window.Helpers.isSmallScreen()) {
return;
}
// If current layout is vertical and current window screen is > small
// Auto update menu collapsed/expanded based on the themeConfig
if (typeof TemplateCustomizer !== 'undefined') {
if (window.templateCustomizer.settings.defaultMenuCollapsed) {
window.Helpers.setCollapsed(true, false);
} else {
window.Helpers.setCollapsed(false, false);
}
}
// Manage menu expanded/collapsed state with local storage support If enableMenuLocalStorage = true in config.js
if (typeof config !== 'undefined') {
if (config.enableMenuLocalStorage) {
try {
if (localStorage.getItem('templateCustomizer-' + templateName + '--LayoutCollapsed') !== null)
window.Helpers.setCollapsed(
localStorage.getItem('templateCustomizer-' + templateName + '--LayoutCollapsed') === 'true',
false
);
} catch (e) {}
}
}
})();

View File

@ -0,0 +1,133 @@
import './../../vendor/libs/leaflet/leaflet'
export const LeafletMapHelper = (() => {
let mapInstance, markerInstance;
const DEFAULT_COORDS = [19.4326, -99.1332]; // Coordenadas de CDMX por defecto
// Valida coordenadas
const isValidCoordinate = (lat, lng) => {
return lat && !isNaN(lat) && lat >= -90 && lat <= 90 && lat !== 0 &&
lng && !isNaN(lng) && lng >= -180 && lng <= 180 && lng !== 0;
};
// Crea opciones del mapa según el modo
const getMapOptions = (mode) => ({
scrollWheelZoom: mode !== 'delete',
dragging: mode !== 'delete',
doubleClickZoom: mode !== 'delete',
boxZoom: mode !== 'delete',
keyboard: mode !== 'delete',
zoomControl: mode !== 'delete',
touchZoom: mode !== 'delete'
});
// Destruir el mapa existente
const destroyMap = () => {
if (mapInstance) {
mapInstance.off();
mapInstance.remove();
mapInstance = null;
}
removeMarker();
};
// Crear marcador en el mapa
const createMarker = (lat, lng, draggable = false, onDragEnd) => {
if (isValidCoordinate(lat, lng)) {
markerInstance = L.marker([lat, lng], { draggable }).addTo(mapInstance)
.bindPopup('<b>Ubicación seleccionada</b>').openPopup();
if (draggable && onDragEnd) {
markerInstance.on('dragend', (e) => {
const { lat, lng } = e.target.getLatLng();
onDragEnd(lat, lng);
});
}
}
};
// Eliminar marcador
const removeMarker = () => {
if (markerInstance) {
markerInstance.remove();
markerInstance = null;
}
};
// Actualizar coordenadas en formulario
const updateCoordinates = (lat, lng, latSelector, lngSelector, livewireInstance) => {
const latInput = document.querySelector(latSelector);
const lngInput = document.querySelector(lngSelector);
if (!latInput || !lngInput) {
console.warn(`⚠️ No se encontró el elemento del DOM para latitud (${latSelector}) o longitud (${lngSelector})`);
return;
}
latInput.value = lat ? lat.toFixed(6) : '';
lngInput.value = lng ? lng.toFixed(6) : '';
if (livewireInstance) {
livewireInstance.lat = lat ? lat.toFixed(6) : null;
livewireInstance.lng = lng ? lng.toFixed(6) : null;
}
};
// Inicializar el mapa
const initializeMap = (locationInputs, mode = 'create', livewireInstance = null) => {
const mapElement = document.getElementById(locationInputs.mapId);
if (!mapElement) {
console.error(`❌ No se encontró el contenedor del mapa con ID: ${locationInputs.mapId}`);
return;
}
let latElement = document.querySelector(locationInputs.lat);
let lngElement = document.querySelector(locationInputs.lng);
if (!latElement || !lngElement) {
console.error(`❌ No se encontraron los campos de latitud (${locationInputs.lat}) o longitud (${locationInputs.lng})`);
return;
}
let lat = parseFloat(latElement.value);
let lng = parseFloat(lngElement.value);
const mapCoords = isValidCoordinate(lat, lng) ? [lat, lng] : DEFAULT_COORDS;
const zoomLevel = isValidCoordinate(lat, lng) ? 16 : 13;
if (mapInstance) destroyMap();
mapInstance = L.map(locationInputs.mapId, getMapOptions(mode)).setView(mapCoords, zoomLevel);
L.tileLayer('https://{s}.tile.osm.org/{z}/{x}/{y}.png').addTo(mapInstance);
if (mode !== 'create') createMarker(lat, lng, mode === 'edit', (lat, lng) => updateCoordinates(lat, lng, locationInputs.lat, locationInputs.lng, livewireInstance));
if (mode !== 'delete') {
mapInstance.on('click', (e) => {
const { lat, lng } = e.latlng;
removeMarker();
createMarker(lat, lng, true, (lat, lng) => updateCoordinates(lat, lng, locationInputs.lat, locationInputs.lng, livewireInstance));
updateCoordinates(lat, lng, locationInputs.lat, locationInputs.lng, livewireInstance);
});
}
/*
const btnClearElement = document.querySelector(locationInputs.btnClear);
if(!btnClearElement){
console.error(`❌ No se encontró el botón de limpiar con ID: ${locationInputs.btnClear}`);return;
}
*/
};
return {
initializeMap,
clearCoordinates: () => {
removeMarker();
},
};
})();
window.LeafletMapHelper = LeafletMapHelper;

View File

@ -0,0 +1,12 @@
export class LocationIQSearchHelper {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = 'https://us1.locationiq.com/v1/search.php';
}
async searchAddress(query) {
const response = await fetch(`${this.baseUrl}?key=${this.apiKey}&q=${query}&format=json`);
if (!response.ok) throw new Error('Error al buscar la dirección');
return await response.json();
}
}

View File

@ -0,0 +1,207 @@
export default class LivewireNotification {
constructor(config = {}) {
const defaultConfig = {
delay: 9000, // Tiempo predeterminado para las notificaciones
onNotificationShown: null, // Callback al mostrar una notificación
onNotificationRemoved: null, // Callback al eliminar una notificación
onNotificationClosed: null // Callback al cerrar una notificación mediante botón
};
this.config = { ...defaultConfig, ...config };
this.initLivewireNotification();
}
/**
* Inicializa la escucha de notificaciones desde Livewire.
*/
initLivewireNotification() {
// Mostrar notificación almacenada después de la recarga
const storedNotification = localStorage.getItem('pendingNotification');
if (storedNotification) {
const event = JSON.parse(storedNotification);
this.showStoredNotification(event);
localStorage.removeItem('pendingNotification'); // Limpiar después de mostrar
}
// Escuchar nuevas notificaciones desde Livewire
Livewire.on('notification', event => {
if (event.deferReload) {
// Guardar la notificación en localStorage para mostrar después de la recarga
localStorage.setItem('pendingNotification', JSON.stringify(event));
window.location.reload();
} else {
// Mostrar la notificación inmediatamente
this.showNotification(event);
}
});
// Escuchar evento personalizado para almacenar la notificación en localStorage
document.addEventListener('store-notification', (event) => {
const notification = {
type: event.detail.type || 'info',
message: event.detail.message || 'Notificación',
delay: event.detail.delay || 5000,
target: event.detail.target || 'body'
};
localStorage.setItem('pendingNotification', JSON.stringify(notification));
});
}
/**
* Método para emitir notificaciones desde JavaScript.
* @param {Object} options - Opciones de la notificación.
* @param {Function} callback - Callback opcional que se ejecutará después de mostrar la notificación.
* @param {number} customTimeout - Timeout personalizado (opcional).
*/
emitNotification(options, callback, customTimeout) {
const event = {
target: options.target || 'body',
message: options.message || 'Notificación',
type: options.type || 'info',
deferReload: options.deferReload || false,
delay: customTimeout || options.delay || this.config.delay // Usar el timeout personalizado o el predeterminado
};
// Mostrar la notificación
this.showNotification(event);
// Ejecutar callback si está definido
if (typeof callback === 'function') {
callback(event);
}
}
/**
* Muestra una notificación almacenada.
* @param {Object} event - Datos del evento de notificación.
*/
showStoredNotification(event) {
this.showNotification(event);
}
/**
* Muestra una notificación.
* @param {Object} event - Datos del evento de notificación.
*/
showNotification(event) {
setTimeout(() => {
const targetElement = document.querySelector(event.target);
if (!targetElement) {
console.error(`Target ${event.target} no encontrado. Mostrando en el contenedor global.`);
this.showInGlobalContainer(event);
return;
}
// Crear un contenedor para notificaciones si no existe
if (!targetElement.querySelector('.notification-container')) {
const container = document.createElement('div');
container.className = 'notification-container';
targetElement.appendChild(container);
}
const notificationContainer = targetElement.querySelector('.notification-container');
const notificationElement = this.renderNotification(notificationContainer, event);
// Callback opcional al mostrar la notificación
if (typeof this.config.onNotificationShown === 'function') {
this.config.onNotificationShown(notificationElement, event);
}
// Configurar el timeout para eliminar la notificación
this.setdelay(notificationElement, event);
// Configurar el evento para el botón de cierre
this.setupCloseButton(notificationElement, event);
}, 5);
}
/**
* Renderiza una notificación en el contenedor global (body).
* @param {Object} event - Datos del evento de notificación.
*/
showInGlobalContainer(event) {
const globalContainer = document.body;
if (!globalContainer.querySelector('.notification-container')) {
const container = document.createElement('div');
container.className = 'notification-container';
globalContainer.appendChild(container);
}
const notificationContainer = globalContainer.querySelector('.notification-container');
const notificationElement = this.renderNotification(notificationContainer, event);
if (typeof this.config.onNotificationShown === 'function') {
this.config.onNotificationShown(notificationElement, event);
}
this.setdelay(notificationElement, event);
this.setupCloseButton(notificationElement, event);
}
/**
* Renderiza una notificación en el contenedor.
* @param {HTMLElement} container - Contenedor de notificaciones.
* @param {Object} event - Evento de notificación con tipo y mensaje.
* @returns {HTMLElement} - Elemento de la notificación recién creada.
*/
renderNotification(container, event) {
const notificationElement = document.createElement('div');
notificationElement.className = `alert alert-${event.type} alert-dismissible fade show`;
notificationElement.role = 'alert';
notificationElement.innerHTML = `${event.message} <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>`;
container.appendChild(notificationElement);
return notificationElement;
}
/**
* Configura un timeout para limpiar una notificación específica.
* @param {HTMLElement} notificationElement - Elemento de la notificación.
* @param {Object} event - Evento asociado a la notificación.
*/
setdelay(notificationElement, event) {
const timeout = event.delay || this.config.delay;
setTimeout(() => {
if (notificationElement && notificationElement.parentElement) {
notificationElement.remove();
// Callback opcional al eliminar la notificación
if (typeof this.config.onNotificationRemoved === 'function') {
this.config.onNotificationRemoved(notificationElement, event);
}
}
}, timeout);
}
/**
* Configura el cierre manual de una notificación mediante el botón "Cerrar".
* @param {HTMLElement} notificationElement - Elemento de la notificación.
* @param {Object} event - Evento asociado a la notificación.
*/
setupCloseButton(notificationElement, event) {
const closeButton = notificationElement.querySelector('.btn-close');
if (closeButton) {
closeButton.addEventListener('click', () => {
notificationElement.remove();
// Callback opcional al cerrar la notificación manualmente
if (typeof this.config.onNotificationClosed === 'function') {
this.config.onNotificationClosed(notificationElement, event);
}
});
}
}
}
if(!window.livewireNotification) {
window.livewireNotification = new LivewireNotification();
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,7 @@
$fa-font-path: 'fontawesome';
$fa-font-size-base: 16px;
@import '@fortawesome/fontawesome-free/scss/fontawesome';
@import '@fortawesome/fontawesome-free/scss/regular';
@import '@fortawesome/fontawesome-free/scss/solid';
@import '@fortawesome/fontawesome-free/scss/brands';

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.4 MiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,101 @@
<div id="template-customizer" class="bg-card">
<a href="javascript:void(0)" class="template-customizer-open-btn" tabindex="-1"></a>
<div class="p-6 m-0 lh-1 border-bottom template-customizer-header position-relative py-4">
<h6 class="template-customizer-t-panel_header mb-1"></h6>
<p class="template-customizer-t-panel_sub_header mb-0 small"></p>
<div class="d-flex align-items-center gap-2 position-absolute end-0 top-0 mt-6 me-5">
<a
href="javascript:void(0)"
class="template-customizer-reset-btn text-heading"
data-bs-toggle="tooltip"
data-bs-placement="bottom"
title="Reset Customizer"
><i class="ti ti-refresh ti-lg"></i
><span class="badge rounded-pill bg-danger badge-dot badge-notifications d-none"></span
></a>
<a href="javascript:void(0)" class="template-customizer-close-btn fw-light text-heading" tabindex="-1">
<i class="ti ti-x ti-lg"></i>
</a>
</div>
</div>
<div class="template-customizer-inner pt-6">
<!-- Theming -->
<div class="template-customizer-theming">
<h5 class="m-0 px-6 py-6">
<span class="template-customizer-t-theming_header bg-label-primary rounded-1 py-1 px-3 small"></span>
</h5>
<!-- Style -->
<div class="m-0 px-6 pb-6 template-customizer-style w-100">
<label for="customizerStyle" class="form-label d-block template-customizer-t-style_label mb-2"></label>
<div class="row px-1 template-customizer-styles-options"></div>
</div>
<!-- Themes -->
<div class="m-0 px-6 template-customizer-themes w-100">
<label for="customizerTheme" class="form-label template-customizer-t-theme_label mb-2"></label>
<div class="row px-1 template-customizer-themes-options"></div>
</div>
</div>
<!--/ Theming -->
<!-- Layout -->
<div class="template-customizer-layout">
<hr class="m-0 px-6 my-6" />
<h5 class="m-0 px-6 pb-6">
<span class="template-customizer-t-layout_header bg-label-primary rounded-2 py-1 px-3 small"></span>
</h5>
<!-- Layout(Menu) -->
<div class="m-0 px-6 pb-6 d-block template-customizer-layouts">
<label for="customizerStyle" class="form-label d-block template-customizer-t-layout_label mb-2"></label>
<div class="row px-1 template-customizer-layouts-options">
<!--? Uncomment If using offcanvas layout -->
<!-- <div class="col-12">
<div class="form-check">
<input class="form-check-input" type="radio" name="layoutRadios" id="layoutRadios-offcanvas"
value="static-offcanvas">
<label class="form-check-label template-customizer-t-layout_offcanvas"
for="layoutRadios-offcanvas"></label>
</div>
</div> -->
<!-- <div class="col-12">
<div class="form-check">
<input class="form-check-input" type="radio" name="layoutRadios" id="layoutRadios-fixed_offcanvas"
value="fixed-offcanvas">
<label class="form-check-label template-customizer-t-layout_fixed_offcanvas"
for="layoutRadios-fixed_offcanvas"></label>
</div>
</div> -->
</div>
</div>
<!-- Header Options for Horizontal -->
<div class="m-0 px-6 pb-6 template-customizer-headerOptions w-100">
<label for="customizerHeader" class="form-label template-customizer-t-layout_header_label mb-2"></label>
<div class="row px-1 template-customizer-header-options"></div>
</div>
<!-- Fixed navbar -->
<div class="m-0 px-6 pb-6 template-customizer-layoutNavbarOptions w-100">
<label for="customizerNavbar" class="form-label template-customizer-t-layout_navbar_label mb-2"></label>
<div class="row px-1 template-customizer-navbar-options"></div>
</div>
<!-- Content -->
<div class="m-0 px-6 pb-6 template-customizer-content w-100">
<label for="customizerContent" class="form-label template-customizer-t-content_label mb-2"></label>
<div class="row px-1 template-customizer-content-options"></div>
</div>
<!-- Directions -->
<div class="m-0 px-6 pb-6 template-customizer-directions w-100">
<label for="customizerDirection" class="form-label template-customizer-t-direction_label mb-2"></label>
<div class="row px-1 template-customizer-directions-options"></div>
</div>
</div>
<!--/ Layout -->
</div>
</div>

View File

@ -0,0 +1,342 @@
/*
* Template Customizer Style
**/
$customizer-width: 400px;
$customizer-width-sm: 300px;
$customizer-hide-width: 1200px;
$customizer-spacer: 20px;
$customizer-font-size: inherit;
$open-btn-size: 38px;
$open-btn-spacer: 0;
$open-btn-font-size: 18px;
$open-btn-top: 180px;
$open-btn-top-md: 145px;
$open-btn-bg: var(--bs-primary);
$open-btn-bg-dark: var(--bs-primary);
$open-btn-color: #fff;
$open-btn-border-radius: 0.375rem;
$open-customizer-primary-color: var(--bs-primary);
#template-customizer {
font-family: 'Public Sans', BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif,
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol' !important;
font-size: $customizer-font-size !important;
position: fixed;
top: 0;
right: 0;
height: 100%;
z-index: 99999999;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
width: $customizer-width;
-webkit-box-shadow: 0px 5px 30px 0px rgba(47, 43, 61, 0.18);
box-shadow: 0px 5px 30px 0px rgba(47, 43, 61, 0.18);
-webkit-transition: all 0.2s ease-in;
-o-transition: all 0.2s ease-in;
transition: all 0.2s ease-in;
-webkit-transform: translateX($customizer-width + $customizer-spacer);
-ms-transform: translateX($customizer-width + $customizer-spacer);
transform: translateX($customizer-width + $customizer-spacer);
.dark-style & {
-webkit-box-shadow: 0px 5px 30px 0px rgba(19, 17, 32, 0.24);
box-shadow: 0px 5px 30px 0px rgba(19, 17, 32, 0.24);
}
h5 {
position: relative;
font-size: 11px;
}
> h5 {
flex: 0 0 auto;
}
.disabled {
color: #d1d2d3 !important;
}
.form-label {
font-size: 0.9375rem;
}
.form-check-label {
font-size: 0.8125rem;
}
&.template-customizer-open {
-webkit-transition-delay: 0.1s;
-o-transition-delay: 0.1s;
transition-delay: 0.1s;
-webkit-transform: none !important;
-ms-transform: none !important;
transform: none !important;
.custom-option.checked {
color: $open-customizer-primary-color;
border-width: 2px;
margin: 0;
}
}
.template-customizer-header {
a:hover {
color: inherit !important;
}
}
// Customizer button
.template-customizer-open-btn {
position: absolute;
top: $open-btn-top;
@media (max-width: 991.98px) {
top: $open-btn-top-md;
}
left: 0;
z-index: -1;
display: block;
width: $open-btn-size;
height: $open-btn-size;
border-top-left-radius: $open-btn-border-radius;
border-bottom-left-radius: $open-btn-border-radius;
background: $open-btn-bg;
box-shadow: 0px 2px 6px 0px rgba(115, 103, 240, 0.3);
color: $open-btn-color !important;
text-align: center;
font-size: $open-btn-font-size !important;
line-height: $open-btn-size;
opacity: 1;
-webkit-transition: all 0.1s linear 0.2s;
-o-transition: all 0.1s linear 0.2s;
transition: all 0.1s linear 0.2s;
-webkit-transform: translateX(-($open-btn-size + $customizer-spacer + $open-btn-spacer));
-ms-transform: translateX(-($open-btn-size + $customizer-spacer + $open-btn-spacer));
transform: translateX(-($open-btn-size + $customizer-spacer + $open-btn-spacer));
.dark-style & {
background: $open-btn-bg-dark;
}
&::before {
content: '';
width: 22px;
height: 22px;
display: block;
background-size: 100% 100%;
position: absolute;
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAABClJREFUaEPtmY1RFEEQhbsjUCIQIhAiUCNQIxAiECIQIxAiECIAIpAMhAiECIQI2vquZqnZvp6fhb3SK5mqq6Ju92b69bzXf6is+dI1t1+eAfztG5z1BsxsU0S+ici2iPB3vm5E5EpEDlSVv2dZswFIxv8UkZcNy+5EZGcuEHMCOBeR951uvVDVD53vVl+bE8DvDu8Pxtyo6ta/BsByg1R15Bwzqz5/LJgn34CZwfnPInI4BUB6/1hV0cSjVxcAM4PbcBZjL0XklIPN7Is3fLCkdQPpPYw/VNXj5IhPIvJWRIhSl6p60ULWBGBm30Vk123EwRxCuIzWkkjNrCZywith10ewE1Xdq4GoAjCz/RTXW44Ynt+LyBEfT43kYfbj86J3w5Q32DNcRQDpwF+dkQXDMey8xem0L3TEqB4g3PZWad8agBMRgZPeu96D1/C2Zbh3X0p80Op1xxloztN48bMQQNoc7+eLEuAoPSPiIDY4Ooo+E6ixeNXM+D3GERz2U3CIqMstLJUgJQDe+7eq6mub0NYEkLAKwEHkiBQDCZtddZCZ8d6r7JDwFkoARklHRPZUFVDVZWbwGuNrC4EfdOzFrRABh3Wnqhv+d70AEBLGFROPmeHlnM81G69UdSd6IUuM0GgUVn1uqWmg5EmMfBeEyB7Pe3txBkY+rGT8j0J+WXq/BgDkUCaqLgEAnwcRog0veMIqFAAwCy2wnw+bI2GaGboBgF9k5N0o0rUSGUb4eO0BeO9j/GYhkSHMHMTIqwGARX6p6a+nlPBl8kZuXMD9j6pKfF9aZuaFOdJCEL5D4eYb9wCYVCanrBmGyii/tIq+SLj/HQBCaM5bLzwfPqdQ6FpVHyra4IbuVbXaY7dETC2ESPNNWiIOi69CcdgSMXsh4tNSUiklMgwmC0aNd08Y5WAES6HHehM4gu97wyhBgWpgqXsrASglprDy7CwhehMZOSbK6JMSma+Fio1KltCmlBIj7gfZOGx8ppQSXrhzFnOhJ/31BDkjFHRvOd09x0mRBA9SFgxUgHpQg0q0t5ymPMlL+EnldFTfDA0NAmf+OTQ0X0sRouf7NNkYGhrOYNrxtIaGg83MNzVDSe3LXLhP7O/yrCsCz1zlWTpjWkuZAOBpX3yVnLqI1yLCOKU6qMrmP7SSrUEw54XF4WBIK5FxCMOr3lVsfGqNSmPzBXUnJTIX1jyVBq9wO6UObOpgC5GjO98vFKnTdQMZXxEsWZlDiCZMIxAbNxQOqlpVZtobejBaZNoBnRDzMFpkxvTQOD36BlrcySZuI6p1ACB6LU3wWuf5581+oHfD1vi89bz3nFUC8Nm7ZlP3nKkFbM4bWPt/MSFwklprYItwt6cmvpWJ2IVcQBCz6bLysSCv3SaANCiTsnaNRrNRqMXVVT1/BrAqz/buu/Y38Ad3KC5PARej0QAAAABJRU5ErkJggg==');
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
// Customizer Hidden
.customizer-hide & {
display: none;
}
[dir='rtl'] & {
border-radius: 0;
border-top-right-radius: $open-btn-border-radius;
border-bottom-right-radius: $open-btn-border-radius;
&::before {
margin-left: -2px;
}
}
}
&.template-customizer-open .template-customizer-open-btn {
opacity: 0;
-webkit-transition-delay: 0s;
-o-transition-delay: 0s;
transition-delay: 0s;
-webkit-transform: none !important;
-ms-transform: none !important;
transform: none !important;
}
// Customizer inner
.template-customizer-inner {
position: relative;
overflow: auto;
-webkit-box-flex: 0;
-ms-flex: 0 1 auto;
flex: 0 1 auto;
opacity: 1;
-webkit-transition: opacity 0.2s;
-o-transition: opacity 0.2s;
transition: opacity 0.2s;
> div:first-child {
> hr:first-of-type {
display: none !important;
}
> h5:first-of-type {
padding-top: 0 !important;
}
}
}
// Theme
.template-customizer-themes-inner {
position: relative;
opacity: 1;
-webkit-transition: opacity 0.2s;
-o-transition: opacity 0.2s;
transition: opacity 0.2s;
}
.template-customizer-theme-item {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
align-items: center;
-ms-flex-align: center;
-webkit-box-flex: 1;
-ms-flex: 1 1 100%;
flex: 1 1 100%;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
margin-bottom: 10px;
padding: 0 24px;
width: 100%;
cursor: pointer;
input {
position: absolute;
z-index: -1; // Put the input behind the label so it doesn't overlay text
opacity: 0;
}
input ~ span {
opacity: 0.25;
-webkit-transition: all 0.2s;
-o-transition: all 0.2s;
transition: all 0.2s;
}
.template-customizer-theme-checkmark {
display: inline-block;
width: 6px;
height: 12px;
border-right: 1px solid;
border-bottom: 1px solid;
opacity: 0;
-webkit-transition: all 0.2s;
-o-transition: all 0.2s;
transition: all 0.2s;
-webkit-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
[dir='rtl'] & {
border-right: none;
border-left: 1px solid;
-webkit-transform: rotate(-45deg);
-ms-transform: rotate(-45deg);
transform: rotate(-45deg);
}
}
input:checked:not([disabled]) ~ span,
&:hover input:not([disabled]) ~ span {
opacity: 1;
}
input:checked:not([disabled]) ~ span .template-customizer-theme-checkmark {
opacity: 1;
}
}
.template-customizer-theme-colors {
span {
display: block;
margin: 0 1px;
width: 10px;
height: 10px;
border-radius: 50%;
-webkit-box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1) inset;
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1) inset;
}
}
&.template-customizer-loading .template-customizer-inner,
&.template-customizer-loading-theme .template-customizer-themes-inner {
opacity: 0.2;
&::after {
content: '';
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 999;
display: block;
}
}
}
@media (max-width: $customizer-hide-width) {
#template-customizer {
display: none;
visibility: hidden !important;
}
}
@media (max-width: 575.98px) {
#template-customizer {
width: $customizer-width-sm;
-webkit-transform: translateX($customizer-width-sm + $customizer-spacer);
-ms-transform: translateX($customizer-width-sm + $customizer-spacer);
transform: translateX($customizer-width-sm + $customizer-spacer);
}
}
.layout-menu-100vh #template-customizer {
height: 100vh;
}
// RTL
//
[dir='rtl'] {
#template-customizer {
right: auto;
left: 0;
-webkit-transform: translateX(-($customizer-width + $customizer-spacer));
-ms-transform: translateX(-($customizer-width + $customizer-spacer));
transform: translateX(-($customizer-width + $customizer-spacer));
}
#template-customizer .template-customizer-open-btn {
right: 0;
left: auto;
-webkit-transform: translateX($open-btn-size + $customizer-spacer + $open-btn-spacer);
-ms-transform: translateX($open-btn-size + $customizer-spacer + $open-btn-spacer);
transform: translateX($open-btn-size + $customizer-spacer + $open-btn-spacer);
}
#template-customizer .template-customizer-close-btn {
right: auto;
left: 0;
}
}
#template-customizer .template-customizer-layouts-options[disabled] {
opacity: 0.5;
pointer-events: none;
}
// ! FIX: mode switch position in RTL
[dir='rtl'] {
.template-customizer-t-style_switch_light {
padding-right: 0 !important;
}
}

View File

@ -0,0 +1,7 @@
import * as bootstrap from 'bootstrap'
try {
window.bootstrap = bootstrap
} catch (e) {}
export { bootstrap }

View File

@ -0,0 +1,73 @@
// Add onHover event for dropdowns
;(function ($) {
if (!$ || !$.fn) return
const SELECTOR = '[data-bs-toggle=dropdown][data-trigger=hover]'
const TIMEOUT = 150
function openDropdown($i) {
let t = $i.data('dd-timeout')
if (t) {
clearTimeout(t)
t = null
$i.data('dd-timeout', t)
}
if ($i.attr('aria-expanded') !== 'true') $i.dropdown('toggle')
}
function closeDropdown($i) {
let t = $i.data('dd-timeout')
if (t) clearTimeout(t)
t = setTimeout(() => {
let t2 = $i.data('dd-timeout')
if (t2) {
clearTimeout(t2)
t2 = null
$i.data('dd-timeout', t2)
}
if ($i.attr('aria-expanded') === 'true') $i.dropdown('toggle')
}, TIMEOUT)
$i.data('dd-timeout', t)
}
$(function () {
$('body')
.on('mouseenter', `${SELECTOR}, ${SELECTOR} ~ .dropdown-menu`, function () {
const $toggle = $(this).hasClass('dropdown-toggle') ? $(this) : $(this).prev('.dropdown-toggle')
const $dropdown = $(this).hasClass('dropdown-menu') ? $(this) : $(this).next('.dropdown-menu')
if (window.getComputedStyle($dropdown[0], null).getPropertyValue('position') === 'static') return
// Set hovered flag
if ($(this).is(SELECTOR)) {
$(this).data('hovered', true)
}
openDropdown($(this).hasClass('dropdown-toggle') ? $(this) : $(this).prev('.dropdown-toggle'))
})
.on('mouseleave', `${SELECTOR}, ${SELECTOR} ~ .dropdown-menu`, function () {
const $toggle = $(this).hasClass('dropdown-toggle') ? $(this) : $(this).prev('.dropdown-toggle')
const $dropdown = $(this).hasClass('dropdown-menu') ? $(this) : $(this).next('.dropdown-menu')
if (window.getComputedStyle($dropdown[0], null).getPropertyValue('position') === 'static') return
// Remove hovered flag
if ($(this).is(SELECTOR)) {
$(this).data('hovered', false)
}
closeDropdown($(this).hasClass('dropdown-toggle') ? $(this) : $(this).prev('.dropdown-toggle'))
})
.on('hide.bs.dropdown', function (e) {
if ($(this).find(SELECTOR).data('hovered')) e.preventDefault()
})
})
})(window.jQuery)

1151
resources/assets/vendor/js/helpers.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,206 @@
const TIMEOUT = 150
class MegaDropdown {
constructor(element, options = {}) {
this._onHover = options.trigger === 'hover' || element.getAttribute('data-trigger') === 'hover'
this._container = MegaDropdown._findParent(element, 'mega-dropdown')
if (!this._container) return
this._menu = this._container.querySelector('.dropdown-toggle ~ .dropdown-menu')
if (!this._menu) return
element.setAttribute('aria-expanded', 'false')
this._el = element
this._bindEvents()
}
open() {
if (this._timeout) {
clearTimeout(this._timeout)
this._timeout = null
}
if (this._focusTimeout) {
clearTimeout(this._focusTimeout)
this._focusTimeout = null
}
if (this._el.getAttribute('aria-expanded') !== 'true') {
this._triggerEvent('show')
this._container.classList.add('show')
this._menu.classList.add('show')
this._el.setAttribute('aria-expanded', 'true')
this._el.focus()
this._triggerEvent('shown')
}
}
close(force) {
if (this._timeout) {
clearTimeout(this._timeout)
this._timeout = null
}
if (this._focusTimeout) {
clearTimeout(this._focusTimeout)
this._focusTimeout = null
}
if (this._onHover && !force) {
this._timeout = setTimeout(() => {
if (this._timeout) {
clearTimeout(this._timeout)
this._timeout = null
}
this._close()
}, TIMEOUT)
} else {
this._close()
}
}
toggle() {
// eslint-disable-next-line no-unused-expressions
this._el.getAttribute('aria-expanded') === 'true' ? this.close(true) : this.open()
}
destroy() {
this._unbindEvents()
this._el = null
if (this._timeout) {
clearTimeout(this._timeout)
this._timeout = null
}
if (this._focusTimeout) {
clearTimeout(this._focusTimeout)
this._focusTimeout = null
}
}
_close() {
if (this._el.getAttribute('aria-expanded') === 'true') {
this._triggerEvent('hide')
this._container.classList.remove('show')
this._menu.classList.remove('show')
this._el.setAttribute('aria-expanded', 'false')
this._triggerEvent('hidden')
}
}
_bindEvents() {
this._elClickEvnt = e => {
e.preventDefault()
this.toggle()
}
this._el.addEventListener('click', this._elClickEvnt)
this._bodyClickEvnt = e => {
if (!this._container.contains(e.target) && this._container.classList.contains('show')) {
this.close(true)
}
}
document.body.addEventListener('click', this._bodyClickEvnt, true)
this._menuClickEvnt = e => {
if (e.target.classList.contains('mega-dropdown-link')) {
this.close(true)
}
}
this._menu.addEventListener('click', this._menuClickEvnt, true)
this._focusoutEvnt = () => {
if (this._focusTimeout) {
clearTimeout(this._focusTimeout)
this._focusTimeout = null
}
if (this._el.getAttribute('aria-expanded') !== 'true') return
this._focusTimeout = setTimeout(() => {
if (
document.activeElement.tagName.toUpperCase() !== 'BODY' &&
MegaDropdown._findParent(document.activeElement, 'mega-dropdown') !== this._container
) {
this.close(true)
}
}, 100)
}
this._container.addEventListener('focusout', this._focusoutEvnt, true)
if (this._onHover) {
this._enterEvnt = () => {
if (window.getComputedStyle(this._menu, null).getPropertyValue('position') === 'static') return
this.open()
}
this._leaveEvnt = () => {
if (window.getComputedStyle(this._menu, null).getPropertyValue('position') === 'static') return
this.close()
}
this._el.addEventListener('mouseenter', this._enterEvnt)
this._menu.addEventListener('mouseenter', this._enterEvnt)
this._el.addEventListener('mouseleave', this._leaveEvnt)
this._menu.addEventListener('mouseleave', this._leaveEvnt)
}
}
_unbindEvents() {
if (this._elClickEvnt) {
this._el.removeEventListener('click', this._elClickEvnt)
this._elClickEvnt = null
}
if (this._bodyClickEvnt) {
document.body.removeEventListener('click', this._bodyClickEvnt, true)
this._bodyClickEvnt = null
}
if (this._menuClickEvnt) {
this._menu.removeEventListener('click', this._menuClickEvnt, true)
this._menuClickEvnt = null
}
if (this._focusoutEvnt) {
this._container.removeEventListener('focusout', this._focusoutEvnt, true)
this._focusoutEvnt = null
}
if (this._enterEvnt) {
this._el.removeEventListener('mouseenter', this._enterEvnt)
this._menu.removeEventListener('mouseenter', this._enterEvnt)
this._enterEvnt = null
}
if (this._leaveEvnt) {
this._el.removeEventListener('mouseleave', this._leaveEvnt)
this._menu.removeEventListener('mouseleave', this._leaveEvnt)
this._leaveEvnt = null
}
}
static _findParent(el, cls) {
if (el.tagName.toUpperCase() === 'BODY') return null
el = el.parentNode
while (el.tagName.toUpperCase() !== 'BODY' && !el.classList.contains(cls)) {
el = el.parentNode
}
return el.tagName.toUpperCase() !== 'BODY' ? el : null
}
_triggerEvent(event) {
if (document.createEvent) {
let customEvent
if (typeof Event === 'function') {
customEvent = new Event(event)
} else {
customEvent = document.createEvent('Event')
customEvent.initEvent(event, false, true)
}
this._container.dispatchEvent(customEvent)
} else {
this._container.fireEvent(`on${event}`, document.createEventObject())
}
}
}
window.MegaDropdown = MegaDropdown
export { MegaDropdown }

991
resources/assets/vendor/js/menu.js vendored Normal file
View File

@ -0,0 +1,991 @@
const TRANSITION_EVENTS = ['transitionend', 'webkitTransitionEnd', 'oTransitionEnd']
// const TRANSITION_PROPERTIES = ['transition', 'MozTransition', 'webkitTransition', 'WebkitTransition', 'OTransition']
const DELTA = 5
class Menu {
constructor(el, config = {}, _PS = null) {
this._el = el
this._horizontal = config.orientation === 'horizontal'
this._animate = config.animate !== false
this._accordion = config.accordion !== false
this._showDropdownOnHover = Boolean(config.showDropdownOnHover)
this._closeChildren = Boolean(config.closeChildren)
this._rtl = document.documentElement.getAttribute('dir') === 'rtl' || document.body.getAttribute('dir') === 'rtl'
this._onOpen = config.onOpen || (() => {})
this._onOpened = config.onOpened || (() => {})
this._onClose = config.onClose || (() => {})
this._onClosed = config.onClosed || (() => {})
this._psScroll = null
this._topParent = null
this._menuBgClass = null
el.classList.add('menu')
el.classList[this._animate ? 'remove' : 'add']('menu-no-animation')
if (!this._horizontal) {
el.classList.add('menu-vertical')
el.classList.remove('menu-horizontal')
const PerfectScrollbarLib = _PS || window.PerfectScrollbar
if (PerfectScrollbarLib) {
this._scrollbar = new PerfectScrollbarLib(el.querySelector('.menu-inner'), {
suppressScrollX: true,
wheelPropagation: !Menu._hasClass('layout-menu-fixed layout-menu-fixed-offcanvas')
})
window.Helpers.menuPsScroll = this._scrollbar
} else {
el.querySelector('.menu-inner').classList.add('overflow-auto')
}
} else {
el.classList.add('menu-horizontal')
el.classList.remove('menu-vertical')
this._inner = el.querySelector('.menu-inner')
const container = this._inner.parentNode
this._prevBtn = el.querySelector('.menu-horizontal-prev')
if (!this._prevBtn) {
this._prevBtn = document.createElement('a')
this._prevBtn.href = '#'
this._prevBtn.className = 'menu-horizontal-prev'
container.appendChild(this._prevBtn)
}
this._wrapper = el.querySelector('.menu-horizontal-wrapper')
if (!this._wrapper) {
this._wrapper = document.createElement('div')
this._wrapper.className = 'menu-horizontal-wrapper'
this._wrapper.appendChild(this._inner)
container.appendChild(this._wrapper)
}
this._nextBtn = el.querySelector('.menu-horizontal-next')
if (!this._nextBtn) {
this._nextBtn = document.createElement('a')
this._nextBtn.href = '#'
this._nextBtn.className = 'menu-horizontal-next'
container.appendChild(this._nextBtn)
}
this._innerPosition = 0
this.update()
}
// Add data attribute for bg color class of menu
const menuClassList = el.classList
for (let i = 0; i < menuClassList.length; i++) {
if (menuClassList[i].startsWith('bg-')) {
this._menuBgClass = menuClassList[i]
}
}
el.setAttribute('data-bg-class', this._menuBgClass)
// Switch to vertical menu on small screen for horizontal menu layout on page load
if (this._horizontal && window.innerWidth < window.Helpers.LAYOUT_BREAKPOINT) {
this.switchMenu('vertical')
} else {
this._bindEvents()
}
// Link menu instance to element
el.menuInstance = this
}
_bindEvents() {
// Click Event
this._evntElClick = e => {
// Find top parent element
if (e.target.closest('ul') && e.target.closest('ul').classList.contains('menu-inner')) {
const menuItem = Menu._findParent(e.target, 'menu-item', false)
// eslint-disable-next-line prefer-destructuring
if (menuItem) this._topParent = menuItem.childNodes[0]
}
const toggleLink = e.target.classList.contains('menu-toggle')
? e.target
: Menu._findParent(e.target, 'menu-toggle', false)
if (toggleLink) {
e.preventDefault()
if (toggleLink.getAttribute('data-hover') !== 'true') {
this.toggle(toggleLink)
}
}
}
if ((!this._showDropdownOnHover && this._horizontal) || !this._horizontal || window.Helpers.isMobileDevice)
this._el.addEventListener('click', this._evntElClick)
this._evntWindowResize = () => {
this.update()
if (this._lastWidth !== window.innerWidth) {
this._lastWidth = window.innerWidth
this.update()
}
const horizontalMenuTemplate = document.querySelector("[data-template^='horizontal-menu']")
if (!this._horizontal && !horizontalMenuTemplate) this.manageScroll()
}
window.addEventListener('resize', this._evntWindowResize)
if (this._horizontal) {
this._evntPrevBtnClick = e => {
e.preventDefault()
if (this._prevBtn.classList.contains('disabled')) return
this._slide('prev')
}
this._prevBtn.addEventListener('click', this._evntPrevBtnClick)
this._evntNextBtnClick = e => {
e.preventDefault()
if (this._nextBtn.classList.contains('disabled')) return
this._slide('next')
}
this._nextBtn.addEventListener('click', this._evntNextBtnClick)
this._evntBodyClick = e => {
if (!this._inner.contains(e.target) && this._el.querySelectorAll('.menu-inner > .menu-item.open').length)
this.closeAll()
}
document.body.addEventListener('click', this._evntBodyClick)
if (this._showDropdownOnHover) {
/** ***********************************************
* Horizontal Menu Mouse Over Event
* ? e.target !== e.currentTarget condition to disable mouseover event on whole menu navbar
* ? !e.target.parentNode.classList.contains('open') to disable mouseover events on icon, text and dropdown arrow
*/
this._evntElMouseOver = e => {
if (e.target !== e.currentTarget && !e.target.parentNode.classList.contains('open')) {
const toggleLink = e.target.classList.contains('menu-toggle') ? e.target : null
if (toggleLink) {
e.preventDefault()
if (toggleLink.getAttribute('data-hover') !== 'true') {
this.toggle(toggleLink)
}
}
}
e.stopPropagation()
}
if (this._horizontal && window.screen.width > window.Helpers.LAYOUT_BREAKPOINT) {
this._el.addEventListener('mouseover', this._evntElMouseOver)
}
/** ***********************************************
* Horizontal Menu Mouse Out Event
* ? e.target !== e.currentTarget condition to disable mouseout event on whole menu navbar
* ? mouseOutEl.parentNode.classList.contains('open') to check if the mouseout element has open class or not
* ? !mouseOutEl.classList.contains('menu-toggle') to check if mouseout was from single menu item and not from the one which has submenu
* ? !mouseOverEl.parentNode.classList.contains('menu-link') to disable mouseout event for icon, text and dropdown arrow
*/
this._evntElMouseOut = e => {
const mainEl = e.currentTarget
const mouseOutEl = e.target
const mouseOverEl = e.toElement || e.relatedTarget
// Find absolute parent of any menu item from which mouseout event triggered
if (mouseOutEl.closest('ul') && mouseOutEl.closest('ul').classList.contains('menu-inner')) {
this._topParent = mouseOutEl
}
if (
mouseOutEl !== mainEl &&
(mouseOutEl.parentNode.classList.contains('open') || !mouseOutEl.classList.contains('menu-toggle')) &&
mouseOverEl &&
mouseOverEl.parentNode &&
!mouseOverEl.parentNode.classList.contains('menu-link')
) {
// When mouse goes totally out of menu items, check mouse over element to confirm it's not the child of menu, once confirmed close the menu
if (this._topParent && !Menu.childOf(mouseOverEl, this._topParent.parentNode)) {
const toggleLink = this._topParent.classList.contains('menu-toggle') ? this._topParent : null
if (toggleLink) {
e.preventDefault()
if (toggleLink.getAttribute('data-hover') !== 'true') {
this.toggle(toggleLink)
this._topParent = null
}
}
}
// When mouse enter the sub menu, check if it's child of the initially mouse overed menu item(Actual Parent),
// if it's the parent do not close the sub menu else close the sub menu
if (Menu.childOf(mouseOverEl, mouseOutEl.parentNode)) {
return
}
const toggleLink = mouseOutEl.classList.contains('menu-toggle') ? mouseOutEl : null
if (toggleLink) {
e.preventDefault()
if (toggleLink.getAttribute('data-hover') !== 'true') {
this.toggle(toggleLink)
}
}
}
e.stopPropagation()
}
if (this._horizontal && window.screen.width > window.Helpers.LAYOUT_BREAKPOINT) {
this._el.addEventListener('mouseout', this._evntElMouseOut)
}
}
}
}
static childOf(/* child node */ c, /* parent node */ p) {
// returns boolean
if (c.parentNode) {
while ((c = c.parentNode) && c !== p);
return !!c
}
return false
}
_unbindEvents() {
if (this._evntElClick) {
this._el.removeEventListener('click', this._evntElClick)
this._evntElClick = null
}
if (this._evntElMouseOver) {
this._el.removeEventListener('mouseover', this._evntElMouseOver)
this._evntElMouseOver = null
}
if (this._evntElMouseOut) {
this._el.removeEventListener('mouseout', this._evntElMouseOut)
this._evntElMouseOut = null
}
if (this._evntWindowResize) {
window.removeEventListener('resize', this._evntWindowResize)
this._evntWindowResize = null
}
if (this._evntBodyClick) {
document.body.removeEventListener('click', this._evntBodyClick)
this._evntBodyClick = null
}
if (this._evntInnerMousemove) {
this._inner.removeEventListener('mousemove', this._evntInnerMousemove)
this._evntInnerMousemove = null
}
if (this._evntInnerMouseleave) {
this._inner.removeEventListener('mouseleave', this._evntInnerMouseleave)
this._evntInnerMouseleave = null
}
}
static _isRoot(item) {
return !Menu._findParent(item, 'menu-item', false)
}
static _findParent(el, cls, throwError = true) {
if (el.tagName.toUpperCase() === 'BODY') return null
el = el.parentNode
while (el.tagName.toUpperCase() !== 'BODY' && !el.classList.contains(cls)) {
el = el.parentNode
}
el = el.tagName.toUpperCase() !== 'BODY' ? el : null
if (!el && throwError) throw new Error(`Cannot find \`.${cls}\` parent element`)
return el
}
static _findChild(el, cls) {
const items = el.childNodes
const found = []
for (let i = 0, l = items.length; i < l; i++) {
if (items[i].classList) {
let passed = 0
for (let j = 0; j < cls.length; j++) {
if (items[i].classList.contains(cls[j])) passed += 1
}
if (cls.length === passed) found.push(items[i])
}
}
return found
}
static _findMenu(item) {
let curEl = item.childNodes[0]
let menu = null
while (curEl && !menu) {
if (curEl.classList && curEl.classList.contains('menu-sub')) menu = curEl
curEl = curEl.nextSibling
}
if (!menu) throw new Error('Cannot find `.menu-sub` element for the current `.menu-toggle`')
return menu
}
// Has class
static _hasClass(cls, el = window.Helpers.ROOT_EL) {
let result = false
cls.split(' ').forEach(c => {
if (el.classList.contains(c)) result = true
})
return result
}
open(el, closeChildren = this._closeChildren) {
const item = this._findUnopenedParent(Menu._getItem(el, true), closeChildren)
if (!item) return
const toggleLink = Menu._getLink(item, true)
Menu._promisify(this._onOpen, this, item, toggleLink, Menu._findMenu(item))
.then(() => {
if (!this._horizontal || !Menu._isRoot(item)) {
if (this._animate && !this._horizontal) {
window.requestAnimationFrame(() => this._toggleAnimation(true, item, false))
if (this._accordion) this._closeOther(item, closeChildren)
} else if (this._animate) {
this._toggleDropdown(true, item, closeChildren)
// eslint-disable-next-line no-unused-expressions
this._onOpened && this._onOpened(this, item, toggleLink, Menu._findMenu(item))
} else {
item.classList.add('open')
// eslint-disable-next-line no-unused-expressions
this._onOpened && this._onOpened(this, item, toggleLink, Menu._findMenu(item))
if (this._accordion) this._closeOther(item, closeChildren)
}
} else {
this._toggleDropdown(true, item, closeChildren)
// eslint-disable-next-line no-unused-expressions
this._onOpened && this._onOpened(this, item, toggleLink, Menu._findMenu(item))
}
})
.catch(() => {})
}
close(el, closeChildren = this._closeChildren, _autoClose = false) {
const item = Menu._getItem(el, true)
const toggleLink = Menu._getLink(el, true)
if (!item.classList.contains('open') || item.classList.contains('disabled')) return
Menu._promisify(this._onClose, this, item, toggleLink, Menu._findMenu(item), _autoClose)
.then(() => {
if (!this._horizontal || !Menu._isRoot(item)) {
if (this._animate && !this._horizontal) {
window.requestAnimationFrame(() => this._toggleAnimation(false, item, closeChildren))
} else {
item.classList.remove('open')
if (closeChildren) {
const opened = item.querySelectorAll('.menu-item.open')
for (let i = 0, l = opened.length; i < l; i++) opened[i].classList.remove('open')
}
// eslint-disable-next-line no-unused-expressions
this._onClosed && this._onClosed(this, item, toggleLink, Menu._findMenu(item))
}
} else {
this._toggleDropdown(false, item, closeChildren)
// eslint-disable-next-line no-unused-expressions
this._onClosed && this._onClosed(this, item, toggleLink, Menu._findMenu(item))
}
})
.catch(() => {})
}
_closeOther(item, closeChildren) {
const opened = Menu._findChild(item.parentNode, ['menu-item', 'open'])
for (let i = 0, l = opened.length; i < l; i++) {
if (opened[i] !== item) this.close(opened[i], closeChildren)
}
}
toggle(el, closeChildren = this._closeChildren) {
const item = Menu._getItem(el, true)
// const toggleLink = Menu._getLink(el, true)
if (item.classList.contains('open')) this.close(item, closeChildren)
else this.open(item, closeChildren)
}
_toggleDropdown(show, item, closeChildren) {
const menu = Menu._findMenu(item)
const actualItem = item
let subMenuItem = false
if (show) {
if (Menu._findParent(item, 'menu-sub', false)) {
subMenuItem = true
item = this._topParent ? this._topParent.parentNode : item
}
const wrapperWidth = Math.round(this._wrapper.getBoundingClientRect().width)
const position = this._innerPosition
const itemOffset = this._getItemOffset(item)
const itemWidth = Math.round(item.getBoundingClientRect().width)
if (itemOffset - DELTA <= -1 * position) {
this._innerPosition = -1 * itemOffset
} else if (itemOffset + position + itemWidth + DELTA >= wrapperWidth) {
if (itemWidth > wrapperWidth) {
this._innerPosition = -1 * itemOffset
} else {
this._innerPosition = -1 * (itemOffset + itemWidth - wrapperWidth)
}
}
actualItem.classList.add('open')
const menuWidth = Math.round(menu.getBoundingClientRect().width)
if (subMenuItem) {
if (
itemOffset + this._innerPosition + menuWidth * 2 > wrapperWidth &&
menuWidth < wrapperWidth &&
menuWidth >= itemWidth
) {
menu.style.left = [this._rtl ? '100%' : '-100%']
}
} else if (
itemOffset + this._innerPosition + menuWidth > wrapperWidth &&
menuWidth < wrapperWidth &&
menuWidth > itemWidth
) {
menu.style[this._rtl ? 'marginRight' : 'marginLeft'] = `-${menuWidth - itemWidth}px`
}
this._closeOther(actualItem, closeChildren)
this._updateSlider()
} else {
const toggle = Menu._findChild(item, ['menu-toggle'])
// eslint-disable-next-line no-unused-expressions
toggle.length && toggle[0].removeAttribute('data-hover', 'true')
item.classList.remove('open')
menu.style[this._rtl ? 'marginRight' : 'marginLeft'] = null
if (closeChildren) {
const opened = menu.querySelectorAll('.menu-item.open')
for (let i = 0, l = opened.length; i < l; i++) opened[i].classList.remove('open')
}
}
}
_slide(direction) {
const wrapperWidth = Math.round(this._wrapper.getBoundingClientRect().width)
const innerWidth = this._innerWidth
let newPosition
if (direction === 'next') {
newPosition = this._getSlideNextPos()
if (innerWidth + newPosition < wrapperWidth) {
newPosition = wrapperWidth - innerWidth
}
} else {
newPosition = this._getSlidePrevPos()
if (newPosition > 0) newPosition = 0
}
this._innerPosition = newPosition
this.update()
}
_getSlideNextPos() {
const wrapperWidth = Math.round(this._wrapper.getBoundingClientRect().width)
const position = this._innerPosition
let curItem = this._inner.childNodes[0]
let left = 0
while (curItem) {
if (curItem.tagName) {
const curItemWidth = Math.round(curItem.getBoundingClientRect().width)
if (left + position - DELTA <= wrapperWidth && left + position + curItemWidth + DELTA >= wrapperWidth) {
if (curItemWidth > wrapperWidth && left === -1 * position) left += curItemWidth
break
}
left += curItemWidth
}
curItem = curItem.nextSibling
}
return -1 * left
}
_getSlidePrevPos() {
const wrapperWidth = Math.round(this._wrapper.getBoundingClientRect().width)
const position = this._innerPosition
let curItem = this._inner.childNodes[0]
let left = 0
while (curItem) {
if (curItem.tagName) {
const curItemWidth = Math.round(curItem.getBoundingClientRect().width)
if (left - DELTA <= -1 * position && left + curItemWidth + DELTA >= -1 * position) {
if (curItemWidth <= wrapperWidth) left = left + curItemWidth - wrapperWidth
break
}
left += curItemWidth
}
curItem = curItem.nextSibling
}
return -1 * left
}
static _getItem(el, toggle) {
let item = null
const selector = toggle ? 'menu-toggle' : 'menu-link'
if (el.classList.contains('menu-item')) {
if (Menu._findChild(el, [selector]).length) item = el
} else if (el.classList.contains(selector)) {
item = el.parentNode.classList.contains('menu-item') ? el.parentNode : null
}
if (!item) {
throw new Error(`${toggle ? 'Toggable ' : ''}\`.menu-item\` element not found.`)
}
return item
}
static _getLink(el, toggle) {
let found = []
const selector = toggle ? 'menu-toggle' : 'menu-link'
if (el.classList.contains(selector)) found = [el]
else if (el.classList.contains('menu-item')) found = Menu._findChild(el, [selector])
if (!found.length) throw new Error(`\`${selector}\` element not found.`)
return found[0]
}
_findUnopenedParent(item, closeChildren) {
let tree = []
let parentItem = null
while (item) {
if (item.classList.contains('disabled')) {
parentItem = null
tree = []
} else {
if (!item.classList.contains('open')) parentItem = item
tree.push(item)
}
item = Menu._findParent(item, 'menu-item', false)
}
if (!parentItem) return null
if (tree.length === 1) return parentItem
tree = tree.slice(0, tree.indexOf(parentItem))
for (let i = 0, l = tree.length; i < l; i++) {
tree[i].classList.add('open')
if (this._accordion) {
const openedItems = Menu._findChild(tree[i].parentNode, ['menu-item', 'open'])
for (let j = 0, k = openedItems.length; j < k; j++) {
if (openedItems[j] !== tree[i]) {
openedItems[j].classList.remove('open')
if (closeChildren) {
const openedChildren = openedItems[j].querySelectorAll('.menu-item.open')
for (let x = 0, z = openedChildren.length; x < z; x++) {
openedChildren[x].classList.remove('open')
}
}
}
}
}
}
return parentItem
}
_toggleAnimation(open, item, closeChildren) {
const toggleLink = Menu._getLink(item, true)
const menu = Menu._findMenu(item)
Menu._unbindAnimationEndEvent(item)
const linkHeight = Math.round(toggleLink.getBoundingClientRect().height)
item.style.overflow = 'hidden'
const clearItemStyle = () => {
item.classList.remove('menu-item-animating')
item.classList.remove('menu-item-closing')
item.style.overflow = null
item.style.height = null
if (!this._horizontal) this.update()
}
if (open) {
item.style.height = `${linkHeight}px`
item.classList.add('menu-item-animating')
item.classList.add('open')
Menu._bindAnimationEndEvent(item, () => {
clearItemStyle()
this._onOpened(this, item, toggleLink, menu)
})
setTimeout(() => {
item.style.height = `${linkHeight + Math.round(menu.getBoundingClientRect().height)}px`
}, 50)
} else {
item.style.height = `${linkHeight + Math.round(menu.getBoundingClientRect().height)}px`
item.classList.add('menu-item-animating')
item.classList.add('menu-item-closing')
Menu._bindAnimationEndEvent(item, () => {
item.classList.remove('open')
clearItemStyle()
if (closeChildren) {
const opened = item.querySelectorAll('.menu-item.open')
for (let i = 0, l = opened.length; i < l; i++) opened[i].classList.remove('open')
}
this._onClosed(this, item, toggleLink, menu)
})
setTimeout(() => {
item.style.height = `${linkHeight}px`
}, 50)
}
}
static _bindAnimationEndEvent(el, handler) {
const cb = e => {
if (e.target !== el) return
Menu._unbindAnimationEndEvent(el)
handler(e)
}
let duration = window.getComputedStyle(el).transitionDuration
duration = parseFloat(duration) * (duration.indexOf('ms') !== -1 ? 1 : 1000)
el._menuAnimationEndEventCb = cb
TRANSITION_EVENTS.forEach(ev => el.addEventListener(ev, el._menuAnimationEndEventCb, false))
el._menuAnimationEndEventTimeout = setTimeout(() => {
cb({ target: el })
}, duration + 50)
}
_getItemOffset(item) {
let curItem = this._inner.childNodes[0]
let left = 0
while (curItem !== item) {
if (curItem.tagName) {
left += Math.round(curItem.getBoundingClientRect().width)
}
curItem = curItem.nextSibling
}
return left
}
_updateSlider(wrapperWidth = null, innerWidth = null, position = null) {
const _wrapperWidth = wrapperWidth !== null ? wrapperWidth : Math.round(this._wrapper.getBoundingClientRect().width)
const _innerWidth = innerWidth !== null ? innerWidth : this._innerWidth
const _position = position !== null ? position : this._innerPosition
if (_innerWidth < _wrapperWidth || window.innerWidth < window.Helpers.LAYOUT_BREAKPOINT) {
this._prevBtn.classList.add('d-none')
this._nextBtn.classList.add('d-none')
} else {
this._prevBtn.classList.remove('d-none')
this._nextBtn.classList.remove('d-none')
}
if (_innerWidth > _wrapperWidth && window.innerWidth > window.Helpers.LAYOUT_BREAKPOINT) {
if (_position === 0) this._prevBtn.classList.add('disabled')
else this._prevBtn.classList.remove('disabled')
if (_innerWidth + _position <= _wrapperWidth) this._nextBtn.classList.add('disabled')
else this._nextBtn.classList.remove('disabled')
}
}
static _promisify(fn, ...args) {
const result = fn(...args)
if (result instanceof Promise) {
return result
}
if (result === false) {
return Promise.reject()
}
return Promise.resolve()
}
get _innerWidth() {
const items = this._inner.childNodes
let width = 0
for (let i = 0, l = items.length; i < l; i++) {
if (items[i].tagName) {
width += Math.round(items[i].getBoundingClientRect().width)
}
}
return width
}
get _innerPosition() {
return parseInt(this._inner.style[this._rtl ? 'marginRight' : 'marginLeft'] || '0px', 10)
}
set _innerPosition(value) {
this._inner.style[this._rtl ? 'marginRight' : 'marginLeft'] = `${value}px`
return value
}
static _unbindAnimationEndEvent(el) {
const cb = el._menuAnimationEndEventCb
if (el._menuAnimationEndEventTimeout) {
clearTimeout(el._menuAnimationEndEventTimeout)
el._menuAnimationEndEventTimeout = null
}
if (!cb) return
TRANSITION_EVENTS.forEach(ev => el.removeEventListener(ev, cb, false))
el._menuAnimationEndEventCb = null
}
closeAll(closeChildren = this._closeChildren) {
const opened = this._el.querySelectorAll('.menu-inner > .menu-item.open')
for (let i = 0, l = opened.length; i < l; i++) this.close(opened[i], closeChildren)
}
static setDisabled(el, disabled) {
Menu._getItem(el, false).classList[disabled ? 'add' : 'remove']('disabled')
}
static isActive(el) {
return Menu._getItem(el, false).classList.contains('active')
}
static isOpened(el) {
return Menu._getItem(el, false).classList.contains('open')
}
static isDisabled(el) {
return Menu._getItem(el, false).classList.contains('disabled')
}
update() {
if (!this._horizontal) {
if (this._scrollbar) {
this._scrollbar.update()
}
} else {
this.closeAll()
const wrapperWidth = Math.round(this._wrapper.getBoundingClientRect().width)
const innerWidth = this._innerWidth
let position = this._innerPosition
if (wrapperWidth - position > innerWidth) {
position = wrapperWidth - innerWidth
if (position > 0) position = 0
this._innerPosition = position
}
this._updateSlider(wrapperWidth, innerWidth, position)
}
}
manageScroll() {
const { PerfectScrollbar } = window
const menuInner = document.querySelector('.menu-inner')
if (window.innerWidth < window.Helpers.LAYOUT_BREAKPOINT) {
if (this._scrollbar !== null) {
// window.Helpers.menuPsScroll.destroy()
this._scrollbar.destroy()
this._scrollbar = null
}
menuInner.classList.add('overflow-auto')
} else {
if (this._scrollbar === null) {
const menuScroll = new PerfectScrollbar(document.querySelector('.menu-inner'), {
suppressScrollX: true,
wheelPropagation: false
})
// window.Helpers.menuPsScroll = menuScroll
this._scrollbar = menuScroll
}
menuInner.classList.remove('overflow-auto')
}
}
switchMenu(menu) {
// Unbind Events
this._unbindEvents()
// const html = document.documentElement
const navbar = document.querySelector('nav.layout-navbar')
const navbarCollapse = document.querySelector('#navbar-collapse')
/* const fullNavbar = document.querySelector('.layout-navbar-full')
const contentNavbar = document.querySelector('.layout-content-navbar')
const contentWrapper = document.querySelector('.content-wrapper') */
const asideMenuWrapper = document.querySelector('#layout-menu div')
const asideMenu = document.querySelector('#layout-menu')
const horzMenuClasses = ['layout-menu-horizontal', 'menu', 'menu-horizontal', 'container-fluid', 'flex-grow-0']
const vertMenuClasses = ['layout-menu', 'menu', 'menu-vertical']
const horzMenuWrapper = document.querySelector('.menu-horizontal-wrapper')
const menuInner = document.querySelector('.menu-inner')
const brand = document.querySelector('.app-brand')
const menuToggler = document.querySelector('.layout-menu-toggle')
const activeMenuItems = document.querySelectorAll('.menu-inner .active')
/* const layoutPage = document.querySelector('.layout-page')
const layoutContainer = document.querySelector('.layout-container')
const content = document.querySelector('.container-fluid') */
// const { PerfectScrollbar } = window
if (menu === 'vertical') {
this._horizontal = false
asideMenuWrapper.insertBefore(brand, horzMenuWrapper)
asideMenuWrapper.insertBefore(menuInner, horzMenuWrapper)
asideMenuWrapper.classList.add('flex-column', 'p-0')
asideMenu.classList.remove(...asideMenu.classList)
asideMenu.classList.add(...vertMenuClasses, this._menuBgClass)
brand.classList.remove('d-none', 'd-lg-flex')
menuToggler.classList.remove('d-none')
// if (PerfectScrollbar !== undefined) {
// this._psScroll = new PerfectScrollbar(document.querySelector('.menu-inner'), {
// suppressScrollX: true,
// wheelPropagation: !Menu._hasClass('layout-menu-fixed layout-menu-fixed-offcanvas')
// })
// }
menuInner.classList.add('overflow-auto')
// Add open class to active items
for (let i = 0; i < activeMenuItems.length - 1; ++i) {
activeMenuItems[i].classList.add('open')
}
} else {
this._horizontal = true
navbar.children[0].insertBefore(brand, navbarCollapse)
brand.classList.add('d-none', 'd-lg-flex')
horzMenuWrapper.appendChild(menuInner)
asideMenuWrapper.classList.remove('flex-column', 'p-0')
asideMenu.classList.remove(...asideMenu.classList)
asideMenu.classList.add(...horzMenuClasses, this._menuBgClass)
menuToggler.classList.add('d-none')
menuInner.classList.remove('overflow-auto')
// if (PerfectScrollbar !== undefined && this._psScroll !== null) {
// this._psScroll.destroy()
// this._psScroll = null
// }
// Remove open class from active items
for (let i = 0; i < activeMenuItems.length; ++i) {
activeMenuItems[i].classList.remove('open')
}
}
this._bindEvents()
}
destroy() {
if (!this._el) return
this._unbindEvents()
const items = this._el.querySelectorAll('.menu-item')
for (let i = 0, l = items.length; i < l; i++) {
Menu._unbindAnimationEndEvent(items[i])
items[i].classList.remove('menu-item-animating')
items[i].classList.remove('open')
items[i].style.overflow = null
items[i].style.height = null
}
const menus = this._el.querySelectorAll('.menu-menu')
for (let i2 = 0, l2 = menus.length; i2 < l2; i2++) {
menus[i2].style.marginRight = null
menus[i2].style.marginLeft = null
}
this._el.classList.remove('menu-no-animation')
if (this._wrapper) {
this._prevBtn.parentNode.removeChild(this._prevBtn)
this._nextBtn.parentNode.removeChild(this._nextBtn)
this._wrapper.parentNode.insertBefore(this._inner, this._wrapper)
this._wrapper.parentNode.removeChild(this._wrapper)
this._inner.style.marginLeft = null
this._inner.style.marginRight = null
}
this._el.menuInstance = null
delete this._el.menuInstance
this._el = null
this._horizontal = null
this._animate = null
this._accordion = null
this._showDropdownOnHover = null
this._closeChildren = null
this._rtl = null
this._onOpen = null
this._onOpened = null
this._onClose = null
this._onClosed = null
if (this._scrollbar) {
this._scrollbar.destroy()
this._scrollbar = null
}
this._inner = null
this._prevBtn = null
this._wrapper = null
this._nextBtn = null
}
}
window.Menu = Menu
export { Menu }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
import { AutoFocus } from '@form-validation/plugin-auto-focus';
try {
FormValidation.plugins.AutoFocus = AutoFocus;
} catch (e) {}
export { AutoFocus };

View File

@ -0,0 +1,7 @@
import { Bootstrap5 } from '@form-validation/plugin-bootstrap5';
try {
FormValidation.plugins.Bootstrap5 = Bootstrap5;
} catch (e) {}
export { Bootstrap5 };

View File

@ -0,0 +1,4 @@
@import '@form-validation/core/lib/styles/index';
@import '@form-validation/plugin-framework/lib/styles/index';
@import '@form-validation/plugin-message/lib/styles/index';
@import '@form-validation/plugin-bootstrap5/lib/styles/index';

View File

@ -0,0 +1,8 @@
import FormValidation from '@form-validation/bundle/popular'
try {
window.FormValidation = FormValidation;
} catch (e) {}
export { FormValidation };

View File

@ -0,0 +1,414 @@
@-webkit-keyframes spin {
0% {
-webkit-transform: rotate(0);
transform: rotate(0);
}
100% {
-webkit-transform: rotate(359deg);
transform: rotate(359deg);
}
}
@keyframes spin {
0% {
-webkit-transform: rotate(0);
transform: rotate(0);
}
100% {
-webkit-transform: rotate(359deg);
transform: rotate(359deg);
}
}
@-webkit-keyframes burst {
0% {
-webkit-transform: scale(1);
transform: scale(1);
opacity: 1;
}
90% {
-webkit-transform: scale(1.5);
transform: scale(1.5);
opacity: 0;
}
}
@keyframes burst {
0% {
-webkit-transform: scale(1);
transform: scale(1);
opacity: 1;
}
90% {
-webkit-transform: scale(1.5);
transform: scale(1.5);
opacity: 0;
}
}
@-webkit-keyframes flashing {
0% {
opacity: 1;
}
45% {
opacity: 0;
}
90% {
opacity: 1;
}
}
@keyframes flashing {
0% {
opacity: 1;
}
45% {
opacity: 0;
}
90% {
opacity: 1;
}
}
@-webkit-keyframes fade-left {
0% {
-webkit-transform: translateX(0);
transform: translateX(0);
opacity: 1;
}
75% {
-webkit-transform: translateX(-20px);
transform: translateX(-20px);
opacity: 0;
}
}
@keyframes fade-left {
0% {
-webkit-transform: translateX(0);
transform: translateX(0);
opacity: 1;
}
75% {
-webkit-transform: translateX(-20px);
transform: translateX(-20px);
opacity: 0;
}
}
@-webkit-keyframes fade-right {
0% {
-webkit-transform: translateX(0);
transform: translateX(0);
opacity: 1;
}
75% {
-webkit-transform: translateX(20px);
transform: translateX(20px);
opacity: 0;
}
}
@keyframes fade-right {
0% {
-webkit-transform: translateX(0);
transform: translateX(0);
opacity: 1;
}
75% {
-webkit-transform: translateX(20px);
transform: translateX(20px);
opacity: 0;
}
}
@-webkit-keyframes fade-up {
0% {
-webkit-transform: translateY(0);
transform: translateY(0);
opacity: 1;
}
75% {
-webkit-transform: translateY(-20px);
transform: translateY(-20px);
opacity: 0;
}
}
@keyframes fade-up {
0% {
-webkit-transform: translateY(0);
transform: translateY(0);
opacity: 1;
}
75% {
-webkit-transform: translateY(-20px);
transform: translateY(-20px);
opacity: 0;
}
}
@-webkit-keyframes fade-down {
0% {
-webkit-transform: translateY(0);
transform: translateY(0);
opacity: 1;
}
75% {
-webkit-transform: translateY(20px);
transform: translateY(20px);
opacity: 0;
}
}
@keyframes fade-down {
0% {
-webkit-transform: translateY(0);
transform: translateY(0);
opacity: 1;
}
75% {
-webkit-transform: translateY(20px);
transform: translateY(20px);
opacity: 0;
}
}
@-webkit-keyframes tada {
from {
-webkit-transform: scale3d(1, 1, 1);
transform: scale3d(1, 1, 1);
}
10%,
20% {
-webkit-transform: scale3d(0.95, 0.95, 0.95) rotate3d(0, 0, 1, -10deg);
transform: scale3d(0.95, 0.95, 0.95) rotate3d(0, 0, 1, -10deg);
}
30%,
50%,
70%,
90% {
-webkit-transform: scale3d(1, 1, 1) rotate3d(0, 0, 1, 10deg);
transform: scale3d(1, 1, 1) rotate3d(0, 0, 1, 10deg);
}
40%,
60%,
80% {
-webkit-transform: scale3d(1, 1, 1) rotate3d(0, 0, 1, -10deg);
transform: scale3d(1, 1, 1) rotate3d(0, 0, 1, -10deg);
}
to {
-webkit-transform: scale3d(1, 1, 1);
transform: scale3d(1, 1, 1);
}
}
@keyframes tada {
from {
-webkit-transform: scale3d(1, 1, 1);
transform: scale3d(1, 1, 1);
}
10%,
20% {
-webkit-transform: scale3d(0.95, 0.95, 0.95) rotate3d(0, 0, 1, -10deg);
transform: scale3d(0.95, 0.95, 0.95) rotate3d(0, 0, 1, -10deg);
}
30%,
50%,
70%,
90% {
-webkit-transform: scale3d(1, 1, 1) rotate3d(0, 0, 1, 10deg);
transform: scale3d(1, 1, 1) rotate3d(0, 0, 1, 10deg);
}
40%,
60%,
80% {
-webkit-transform: rotate3d(0, 0, 1, -10deg);
transform: rotate3d(0, 0, 1, -10deg);
}
to {
-webkit-transform: scale3d(1, 1, 1);
transform: scale3d(1, 1, 1);
}
}
.ti-spin {
-webkit-animation: spin 2s linear infinite;
animation: spin 2s linear infinite;
}
.ti-spin-hover:hover {
-webkit-animation: spin 2s linear infinite;
animation: spin 2s linear infinite;
}
.ti-tada {
-webkit-animation: tada 1.5s ease infinite;
animation: tada 1.5s ease infinite;
}
.ti-tada-hover:hover {
-webkit-animation: tada 1.5s ease infinite;
animation: tada 1.5s ease infinite;
}
.ti-flashing {
-webkit-animation: flashing 1.5s infinite linear;
animation: flashing 1.5s infinite linear;
}
.ti-flashing-hover:hover {
-webkit-animation: flashing 1.5s infinite linear;
animation: flashing 1.5s infinite linear;
}
.ti-burst {
-webkit-animation: burst 1.5s infinite linear;
animation: burst 1.5s infinite linear;
}
.ti-burst-hover:hover {
-webkit-animation: burst 1.5s infinite linear;
animation: burst 1.5s infinite linear;
}
.ti-fade-up {
-webkit-animation: fade-up 1.5s infinite linear;
animation: fade-up 1.5s infinite linear;
}
.ti-fade-up-hover:hover {
-webkit-animation: fade-up 1.5s infinite linear;
animation: fade-up 1.5s infinite linear;
}
.ti-fade-down {
-webkit-animation: fade-down 1.5s infinite linear;
animation: fade-down 1.5s infinite linear;
}
.ti-fade-down-hover:hover {
-webkit-animation: fade-down 1.5s infinite linear;
animation: fade-down 1.5s infinite linear;
}
.ti-fade-left {
-webkit-animation: fade-left 1.5s infinite linear;
animation: fade-left 1.5s infinite linear;
}
.ti-fade-left-hover:hover {
-webkit-animation: fade-left 1.5s infinite linear;
animation: fade-left 1.5s infinite linear;
}
.ti-fade-right {
-webkit-animation: fade-right 1.5s infinite linear;
animation: fade-right 1.5s infinite linear;
}
.ti-fade-right-hover:hover {
-webkit-animation: fade-right 1.5s infinite linear;
animation: fade-right 1.5s infinite linear;
}
.ti-xs {
font-size: 1rem !important;
}
.ti-sm {
font-size: 1.125rem !important;
}
.ti-md {
font-size: 1.375rem !important;
}
.ti-lg {
font-size: 1.5rem !important;
}
.ti-xl {
font-size: 2.25rem !important;
}
.ti-10px {
&,
&:before {
font-size: 10px;
}
}
.ti-12px {
&,
&:before {
font-size: 12px;
}
}
.ti-14px {
&,
&:before {
font-size: 14px;
}
}
.ti-16px {
&,
&:before {
font-size: 16px;
}
}
.ti-18px {
&,
&:before {
font-size: 18px;
}
}
.ti-20px {
&,
&:before {
font-size: 20px;
}
}
.ti-22px {
&,
&:before {
font-size: 22px;
}
}
.ti-24px {
&,
&:before {
font-size: 24px;
}
}
.ti-26px {
&,
&:before {
font-size: 26px;
}
}
.ti-28px {
&,
&:before {
font-size: 28px;
}
}
.ti-30px {
&,
&:before {
font-size: 30px;
}
}
.ti-32px {
&,
&:before {
font-size: 32px;
}
}
.ti-36px {
&,
&:before {
font-size: 36px;
}
}
.ti-40px {
&,
&:before {
font-size: 40px;
}
}
.ti-42px {
&,
&:before {
font-size: 42px;
}
}
.ti-48px {
&,
&:before {
font-size: 48px;
}
}

View File

@ -0,0 +1 @@
@import 'animate.css/animate';

View File

@ -0,0 +1,93 @@
@import '../../scss/_bootstrap-extended/functions';
@mixin bs-datepicker-theme($background, $color: null) {
$color: if($color, $color, color-contrast($background));
$range-bg: rgba-to-hex(rgba($background, 0.16), $card-bg);
$range-color: $background;
.datepicker {
table {
tr td {
&.active,
&.active.highlighted,
.focused,
span.active,
span.active.disabled,
&.range-start,
&.range-end {
background: $background !important;
color: $color !important;
box-shadow: 0 0.125rem 0.375rem 0 rgba($background, 0.3);
}
&.range,
&.range.highlighted,
&.range.today {
color: $range-color !important;
background: $range-bg !important;
&.focused {
background: rgba-to-hex(rgba($background, 0.24), $card-bg) !important;
}
&.disabled {
background: transparentize($range-bg, 0.5) !important;
color: transparentize($range-color, 0.5) !important;
}
}
&.today:not(.active),
&.today:not(.active):hover {
color: $background;
background-color: rgba-to-hex(rgba($background, 0.16), $card-bg);
}
}
}
}
}
@mixin bs-datepicker-dark-theme($background, $color: null) {
$color: if($color, $color, color-contrast($background));
$range-bg: rgba-to-hex(rgba($background, 0.24), $card-bg);
$range-color: $background;
.datepicker {
table {
tr td {
&.active,
&.active.highlighted,
.focused,
span.active,
span.active.disabled,
&.range-start,
&.range-end {
color: $color !important;
background: $background !important;
box-shadow: 0 0.125rem 0.375rem 0 rgba($background, 0.3);
}
&.range,
&.range.highlighted,
&.range.today {
color: $range-color !important;
background: $range-bg !important;
&.disabled {
color: transparentize($range-color, 0.5) !important;
background: transparentize($range-bg, 0.5) !important;
}
&.focused {
background: rgba-to-hex(rgba($background, 0.24), $card-bg) !important;
}
}
&.today:not(.active),
&.today:not(.active):hover {
color: $background;
background-color: rgba-to-hex(rgba($background, 0.16), $card-bg);
}
}
}
}
}

View File

@ -0,0 +1 @@
import 'bootstrap-datepicker/dist/js/bootstrap-datepicker';

View File

@ -0,0 +1,482 @@
@use '../../scss/_bootstrap-extended/include' as light;
@use '../../scss/_bootstrap-extended/include-dark' as dark;
@import '../../scss/_custom-variables/libs';
$datepicker-arrow-size: 0.45rem !default;
$datepicker-item-width: 2.25rem !default;
$datepicker-item-height: 2.25rem !default;
$white: #fff;
.datepicker {
direction: ltr;
&.dropdown-menu {
padding: 0;
margin: 0;
}
.datepicker-days {
margin: 0.875rem 0.875rem 0.875rem;
}
// Basic styles for next and prev arrows
.next,
.prev {
color: transparent !important;
position: absolute;
top: 0.65rem;
height: 1.875rem;
width: 1.875rem;
border-radius: light.$border-radius-pill;
display: table-caption;
}
// LRT & RTL only styles for arrows
table thead tr th {
&.next {
@include app-ltr {
float: right;
right: 0.125rem;
}
@include app-rtl {
float: left;
left: 0.125rem;
}
}
&.prev {
@include app-ltr {
right: 2.75rem;
}
@include app-rtl {
left: 2.75rem;
}
}
}
&.datepicker-inline {
table {
thead tr th {
&.next {
inset-inline-end: 0.5rem !important;
}
}
}
.datepicker-days {
.datepicker-switch {
top: 0;
}
}
}
// next & prev arrow after style
.next::after,
.prev::after {
content: '';
display: block;
position: absolute;
left: 46%;
top: 46%;
height: $datepicker-arrow-size;
width: $datepicker-arrow-size;
border-radius: 0;
border-style: solid;
transform: rotate(-45deg);
transform-origin: left;
}
.next::after {
margin-left: -$datepicker-arrow-size * 0.35;
border-width: 0 1.9px 1.9px 0;
@include app-rtl {
transform: rotate(-45deg);
border-width: 1.9px 0 0 1.9px;
margin-left: 0;
}
}
.prev::after {
border-width: 1.9px 0 0 1.9px;
@include app-rtl {
transform: rotate(-45deg);
border-width: 0 1.9px 1.9px 0;
margin-left: -$datepicker-arrow-size * 0.5;
}
}
// arrow alignments excluding datepicker-days
.datepicker-months,
.datepicker-years,
.datepicker-decades,
.datepicker-centuries {
.next {
@include app-ltr {
right: 1rem;
}
@include app-rtl {
left: 1rem;
}
}
.prev {
@include app-ltr {
right: 3.4rem;
}
@include app-rtl {
left: 3.4rem;
}
}
}
// switch default styles
.datepicker-switch {
vertical-align: middle;
position: relative;
@include app-ltr {
text-align: left;
}
@include app-rtl {
text-align: right;
}
}
// switch alignments datepicker-days
.datepicker-days {
.datepicker-switch {
top: -4px;
@include app-ltr {
left: -1.68rem;
}
@include app-rtl {
right: -1.68rem;
}
}
}
// switch alignments excluding datepicker-days
.datepicker-months,
.datepicker-years,
.datepicker-decades,
.datepicker-centuries {
.datepicker-switch {
@include app-ltr {
left: 1rem;
}
@include app-rtl {
right: 1rem;
}
}
}
table thead tr:nth-child(2) {
height: 60px !important;
width: 80px;
position: relative;
}
&.datepicker-rtl {
direction: rtl;
table tr td span {
float: right;
}
}
@include app-rtl {
direction: rtl;
}
}
.datepicker table {
user-select: none;
margin: 0;
overflow: hidden;
border-radius: light.$dropdown-border-radius;
tbody {
//! FIX: padding or margin top will not work in table
&:before {
content: '@';
display: block;
line-height: 6px;
text-indent: -99999px;
}
}
}
.datepicker table tr td,
.datepicker table tr th {
font-weight: 400;
text-align: center;
border: none;
&.dow {
font-size: light.$font-size-sm;
}
}
.datepicker table tr td {
border-radius: light.$border-radius-pill;
width: $datepicker-item-width;
height: $datepicker-item-height;
&.day:hover,
&.focused {
cursor: pointer;
}
&.disabled,
&.disabled:hover {
cursor: default;
background: none;
}
&.range {
border-radius: 0 !important;
&.today {
box-shadow: none !important;
}
}
// span.month,
// span.year {
// margin: 0 0.5rem;
// }
&.range-start:not(.range-end) {
@include app-ltr {
border-bottom-right-radius: 0 !important;
border-top-right-radius: 0 !important;
}
@include app-rtl {
border-bottom-left-radius: 0 !important;
border-top-left-radius: 0 !important;
}
}
&.range-end:not(.range-start) {
@include app-ltr {
border-bottom-left-radius: 0 !important;
border-top-left-radius: 0 !important;
}
@include app-rtl {
border-bottom-right-radius: 0 !important;
border-top-right-radius: 0 !important;
}
}
&.selected,
&.selected:hover,
&.selected.highlighted {
color: $white;
}
}
// Styles for datepicker months, years, decades etc
.datepicker table tr td span {
display: block;
float: left;
width: 3.625rem;
height: 2rem;
line-height: 2rem;
cursor: pointer;
&.disabled,
&.disabled:hover {
background: none;
cursor: default;
}
@include app-rtl {
float: right;
}
}
.datepicker .datepicker-switch,
.datepicker .prev,
.datepicker .next,
.datepicker tfoot tr th {
cursor: pointer;
}
.datepicker-months table,
.datepicker-years table,
.datepicker-decades table,
.datepicker-centuries table {
width: (3.375rem * 3) + 2.625rem;
td {
padding: 0 0 0.5rem 0.8125rem;
@include app-rtl {
padding: 0 0.8125rem 0.5rem 0;
}
}
}
.datepicker-dropdown {
left: 0;
top: 0;
padding: 0;
}
.input-daterange input {
text-align: center;
}
// Light style
@if $enable-light-style {
.light-style {
.datepicker-dropdown {
z-index: light.$zindex-popover !important;
box-shadow: light.$card-box-shadow;
}
.datepicker {
th {
&.prev,
&.next {
background-color: light.rgba-to-hex(rgba(light.$black, 0.08), light.$card-bg);
&::after {
border-color: light.$body-color;
}
}
}
&.datepicker-inline {
table {
box-shadow: light.$box-shadow;
}
}
table {
thead {
background-color: light.$card-bg;
tr,
td {
color: light.$headings-color;
}
}
tr td,
tr th {
&.new {
color: light.$text-muted;
}
}
tr td {
&.old,
&.disabled {
color: light.$text-muted;
}
&.cw {
background-color: light.$card-bg;
color: light.$body-color;
}
&.day:hover,
&.focused {
background: light.rgba-to-hex(light.$gray-50, light.$card-bg);
}
}
}
}
.datepicker table tr td span {
border-radius: light.$border-radius;
&:hover,
&.focused {
background: light.rgba-to-hex(light.$gray-50, light.$card-bg);
}
&.disabled,
&.disabled:hover {
color: light.$text-muted;
}
&.old,
&.new {
color: light.$text-muted;
}
}
}
}
// Dark style
@if $enable-dark-style {
.dark-style {
.datepicker-dropdown {
z-index: dark.$zindex-popover !important;
box-shadow: dark.$card-box-shadow;
}
.datepicker {
th {
&.prev,
&.next {
background-color: dark.rgba-to-hex(rgba(dark.$base, 0.08), dark.$card-bg);
&::after {
border-color: dark.$body-color;
}
}
}
&.datepicker-inline {
table {
box-shadow: dark.$card-box-shadow;
}
}
table {
thead {
background-color: dark.$card-bg;
tr,
td {
color: dark.$headings-color;
}
}
tr td,
tr th {
&.new {
color: dark.$text-muted;
}
}
tr td {
color: dark.$body-color;
&.old,
&.disabled {
color: dark.$text-muted;
}
&.cw {
background-color: dark.$card-bg;
color: dark.$body-color;
}
&.day:hover,
&.focused {
background: dark.rgba-to-hex(dark.$gray-50, dark.$card-bg);
}
}
}
}
.datepicker table tr td span {
border-radius: dark.$border-radius;
&:hover,
&.focused {
background: dark.rgba-to-hex(dark.$gray-50, dark.$card-bg);
}
&.disabled,
&.disabled:hover {
color: dark.$text-muted;
}
&.old,
&.new {
color: dark.$text-muted;
}
}
}
}

View File

@ -0,0 +1,81 @@
@import '../../scss/_bootstrap-extended/functions';
@mixin bs-daterangepicker-theme($background, $color: null) {
$color: if($color, $color, color-contrast($background));
$highlighted-bg: rgba-to-hex(rgba($background, 0.16), $card-bg);
$highlighted-color: $background;
.daterangepicker td.active:not(.off) {
background: $background !important;
color: $white;
box-shadow: 0 0.125rem 0.375rem 0 rgba($background, 0.3);
}
.daterangepicker {
.start-date:not(.end-date):not(.off),
.end-date:not(.start-date):not(.off) {
background-color: $background;
color: $white;
border: 0 !important;
&:hover {
background-color: $background !important;
}
}
}
.daterangepicker .input-mini.active {
border-color: $background !important;
}
.daterangepicker td.in-range:not(.start-date):not(.end-date):not(.off) {
color: $highlighted-color !important;
background-color: $highlighted-bg !important;
}
.ranges li.active {
color: $highlighted-color !important;
background-color: $highlighted-bg !important;
}
}
@mixin bs-daterangepicker-dark-theme($background, $color: null) {
$color: if($color, $color, color-contrast($background));
$highlighted-bg: rgba-to-hex(rgba($background, 0.16), $card-bg);
$highlighted-color: $background;
.daterangepicker td.active:not(.off) {
background: $background !important;
color: $white;
box-shadow: 0 0.125rem 0.375rem 0 rgba($background, 0.3);
}
.daterangepicker {
.start-date:not(.end-date):not(.off),
.end-date:not(.start-date):not(.off) {
background-color: $background;
color: $white;
border: 0 !important;
&:hover {
background-color: $background !important;
}
}
}
.daterangepicker .input-mini.active {
border-color: $background !important;
}
.daterangepicker td.in-range:not(.start-date):not(.end-date):not(.off) {
color: $highlighted-color !important;
background-color: $highlighted-bg !important;
}
.ranges li.active {
color: $highlighted-color !important;
background-color: $highlighted-bg !important;
}
}

View File

@ -0,0 +1,18 @@
import 'bootstrap-daterangepicker/daterangepicker';
// Patch detect when weeks are shown
const fnDaterangepicker = $.fn.daterangepicker;
$.fn.daterangepicker = function (options, callback) {
fnDaterangepicker.call(this, options, callback);
if (options && (options.showWeekNumbers || options.showISOWeekNumbers)) {
this.each(function () {
const instance = $(this).data('daterangepicker');
if (instance && instance.container) instance.container.addClass('with-week-numbers');
});
}
return this;
};

View File

@ -0,0 +1,744 @@
@use '../../scss/_bootstrap-extended/include' as light;
@use '../../scss/_bootstrap-extended/include-dark' as dark;
@import '../../scss/_custom-variables/libs';
$daterangepicker-arrow-size: 0.45rem !default;
$daterangepicker-select-width: 3.125rem !default;
$daterangepicker-cell-size: 2.25rem !default;
$daterangepicker-padding: 0.8rem !default;
// Calculate widths
$daterangepicker-width: ($daterangepicker-cell-size * 7)+ ($daterangepicker-padding * 2);
$daterangepicker-width-with-weeks: $daterangepicker-width + $daterangepicker-cell-size;
.daterangepicker {
position: absolute;
max-width: none;
padding: 0.875rem 0 0.5rem;
display: none;
tbody {
//! FIX: padding or margin top will not work in table
&:before {
content: '@';
display: block;
line-height: 6px;
text-indent: -99999px;
}
}
@include app-rtl {
direction: rtl !important;
}
// datepicker header styles
table thead tr:first-child {
height: 52px !important;
position: relative;
}
.calendar-table td {
border-radius: 50rem;
}
// month and year select styles
table thead {
th,
td {
select {
background-color: transparent;
font-weight: light.$font-weight-medium;
}
}
}
}
// prev arrow styles excluding single daterangepicker
.daterangepicker {
.drp-calendar:not(.single).left {
.prev {
@include app-ltr {
left: 0.25rem;
}
@include app-rtl {
right: 0.25rem;
}
}
}
// next arrow styles excluding single daterangepicker
.drp-calendar:not(.single).right {
.next {
@include app-ltr {
right: 0.25rem;
}
@include app-rtl {
left: 0.25rem;
}
}
}
}
.daterangepicker.auto-apply .drp-buttons {
display: none;
}
.daterangepicker.show-calendar .drp-calendar,
.daterangepicker.show-calendar .drp-buttons {
display: block;
}
.daterangepicker .drp-calendar {
display: none;
padding: 0 $daterangepicker-padding $daterangepicker-padding;
&.single .calendar-table {
border: 0;
}
}
.daterangepicker.single {
.drp-selected {
display: none;
}
.daterangepicker .ranges,
.drp-calendar {
float: none;
}
}
.daterangepicker .calendar-table {
border: 0;
// prev & next arrow default styles
.next,
.prev {
position: absolute;
top: 0.65rem;
min-width: unset;
height: 1.875rem;
width: 1.875rem;
border-radius: 50rem;
display: flex;
justify-content: center;
align-items: center;
}
.next span,
.prev span {
display: inline-block;
border-width: 0 1.9px 1.9px 0;
border-style: solid;
border-radius: 0;
height: $daterangepicker-arrow-size;
width: $daterangepicker-arrow-size;
}
.prev span {
margin-right: -$daterangepicker-arrow-size * 0.5;
transform: rotate(135deg);
@include app-rtl {
margin-left: -$daterangepicker-arrow-size * 0.5;
margin-right: 0;
transform: rotate(-45deg);
}
}
.next span {
margin-left: -$daterangepicker-arrow-size * 0.5;
transform: rotate(-45deg);
@include app-rtl {
margin-left: 0;
margin-right: -$daterangepicker-arrow-size * 0.5;
transform: rotate(135deg);
}
}
table {
border: 0;
border-spacing: 0;
border-collapse: collapse;
margin: 0;
width: 100%;
}
th,
td {
vertical-align: middle;
min-width: $daterangepicker-cell-size;
line-height: calc(#{$daterangepicker-cell-size} - 2px);
white-space: nowrap;
text-align: center;
cursor: pointer;
}
td {
height: $daterangepicker-cell-size;
width: $daterangepicker-cell-size;
}
th {
width: $daterangepicker-cell-size;
height: $daterangepicker-cell-size + 0.5rem;
}
tr:first-child th:not(.prev):not(.next) {
height: $daterangepicker-cell-size;
}
// daterangepicker single
.daterangepicker .single {
// arrow alignments
.next {
float: right;
@include app-ltr {
right: 0.625rem;
}
@include app-rtl {
left: 0.625rem;
}
}
.prev {
@include app-ltr {
right: 3.125rem;
}
@include app-rtl {
left: 3.125rem;
}
}
// month alignments
th.month {
position: absolute;
top: 0.5rem;
@include app-ltr {
text-align: left;
left: 0.562rem;
}
@include app-rtl {
text-align: right;
right: 0.562rem;
}
}
}
}
.daterangepicker td {
@include app-ltr {
&.start-date:not(.end-date) {
border-bottom-right-radius: 0 !important;
border-top-right-radius: 0 !important;
}
&.end-date:not(.start-date) {
border-bottom-left-radius: 0 !important;
border-top-left-radius: 0 !important;
}
}
&.in-range:not(.start-date):not(.end-date) {
border-radius: 0 !important;
}
@include app-rtl {
&.start-date:not(.end-date) {
border-bottom-left-radius: 0 !important;
border-top-left-radius: 0 !important;
}
&.end-date:not(.start-date) {
border-bottom-right-radius: 0 !important;
border-top-right-radius: 0 !important;
}
}
}
.daterangepicker td.disabled,
.daterangepicker option.disabled {
cursor: not-allowed;
text-decoration: line-through;
}
.daterangepicker th.month {
width: auto;
}
.daterangepicker select {
&.monthselect,
&.yearselect {
height: auto;
padding: 1px;
margin: 0;
border: 0;
cursor: default;
}
&:focus-visible {
outline: 0;
}
&.monthselect {
width: 46%;
margin-right: 2%;
@include app-rtl {
margin-left: 2%;
margin-right: 0;
}
}
&.yearselect {
width: 40%;
}
&.hourselect,
&.minuteselect,
&.secondselect,
&.ampmselect {
outline: 0;
width: $daterangepicker-select-width;
padding: 2px;
margin: 0 auto;
border-radius: light.$border-radius-sm;
}
}
.daterangepicker .calendar-time {
position: relative;
line-height: 30px;
text-align: center;
margin: 0 auto;
select.disabled {
cursor: not-allowed;
}
}
.daterangepicker .drp-buttons {
padding: $daterangepicker-padding $daterangepicker-padding * 1.5;
clear: both;
display: none;
text-align: right;
vertical-align: middle;
.btn {
margin-left: $daterangepicker-padding * 1.2;
}
@include app-rtl {
text-align: left;
.btn {
margin-left: 0;
margin-right: $daterangepicker-padding * 1.2;
}
}
}
.daterangepicker .drp-selected {
width: 100%;
padding-bottom: $daterangepicker-padding;
display: block;
}
.daterangepicker .ranges {
text-align: left;
float: none;
margin: 0;
// Daterangepicker Ranges spacing
ul {
padding: 0.5rem;
margin: 0 auto;
list-style: none;
width: 100%;
}
li {
border-radius: light.$border-radius;
padding: light.$dropdown-item-padding-y light.$dropdown-item-padding-x;
&:not(:first-child) {
margin-top: 0.125rem;
}
}
@include app-rtl {
text-align: right;
}
}
.daterangepicker.show-calendar .ranges {
border-bottom: 1px solid;
&:empty {
display: none;
}
}
.daterangepicker .drp-calendar.right {
@include app-ltr {
padding-left: 1px;
}
@include app-rtl {
padding-right: 1px;
}
}
// Light style
@if $enable-light-style {
.light-style {
.daterangepicker {
z-index: light.$zindex-popover !important;
border: light.$dropdown-border-width solid light.$dropdown-border-color;
border-radius: light.$border-radius;
width: calc(#{$daterangepicker-width} + calc(#{light.$dropdown-border-width} * 2));
box-shadow: light.$card-box-shadow;
background-color: light.$dropdown-bg;
table thead {
background: light.$dropdown-bg;
th,
td {
color: light.$headings-color;
&.prev,
&.next {
span {
border-color: light.$body-color !important;
}
}
select {
background-color: transparent;
color: light.$headings-color;
}
}
}
&.drop-up {
margin-top: -(light.$dropdown-spacer);
}
&.with-week-numbers {
width: calc(#{$daterangepicker-width-with-weeks} + calc(#{light.$dropdown-border-width} * 2));
}
}
.daterangepicker .calendar-table td {
border-radius: light.$border-radius-pill;
}
.daterangepicker .drp-selected {
font-size: light.$font-size-sm;
}
.daterangepicker .calendar-table thead tr:last-child th {
border-radius: 0 !important;
color: light.$headings-color;
font-size: light.$font-size-sm;
font-weight: light.$font-weight-normal;
}
.daterangepicker th.month {
color: light.$headings-color;
font-weight: light.$font-weight-normal;
}
.daterangepicker td.week,
.daterangepicker th.week {
color: light.$headings-color;
font-weight: light.$font-weight-normal;
}
.daterangepicker td.disabled,
.daterangepicker option.disabled {
color: light.$text-muted;
}
.daterangepicker td.available:not(.active):hover,
.daterangepicker th.available:hover {
background-color: light.$gray-50;
}
.daterangepicker td.off {
color: light.$text-muted;
}
.daterangepicker .ranges li {
cursor: pointer;
padding: light.$dropdown-item-padding-y light.$dropdown-item-padding-x;
&:hover {
background-color: light.$dropdown-link-hover-bg;
}
}
.daterangepicker .calendar-table .next,
.daterangepicker .calendar-table .prev {
background-color: light.$gray-50;
span {
border-color: light.$body-color;
}
}
.daterangepicker select {
&.hourselect,
&.minuteselect,
&.secondselect,
&.ampmselect {
background: light.rgba-to-hex(light.$gray-100, light.$rgba-to-hex-bg);
font-size: light.$font-size-sm;
color: light.$body-color;
border: 1px solid transparent;
option {
background: light.$card-bg;
}
}
// ! FIX: OS Windows and Linux Browsers DD Option color
&.monthselect,
&.yearselect {
option {
color: light.$body-color;
background: light.$input-bg;
&:disabled {
color: light.$text-muted;
}
}
}
}
.daterangepicker .calendar-time select.disabled {
color: light.$text-light;
}
@include light.media-breakpoint-up(md) {
.daterangepicker {
width: auto !important;
&:not(.single) .drp-selected {
width: auto;
padding: 0;
display: inline-block;
}
}
@include app-ltr-style {
.daterangepicker:not(.single) .drp-calendar {
float: left;
&.left {
padding-right: 1rem;
}
}
}
@include app-rtl-style {
.daterangepicker:not(.single) .drp-calendar {
float: right;
&.left {
padding-left: 1rem;
}
}
}
}
@include light.media-breakpoint-up(lg) {
.daterangepicker .ranges {
border-bottom: 0;
}
@include app-ltr-style {
.daterangepicker {
.ranges {
float: left;
}
}
}
@include app-rtl-style {
.daterangepicker {
.ranges {
float: right;
}
}
}
}
}
}
// Dark style
@if $enable-dark-style {
.dark-style {
.daterangepicker {
box-shadow: dark.$card-box-shadow;
width: calc(#{$daterangepicker-width} + calc(#{dark.$dropdown-border-width} * 2));
margin-top: dark.$dropdown-spacer;
background-color: dark.$dropdown-bg;
border: dark.$dropdown-border-width solid dark.$dropdown-border-color;
border-radius: dark.$border-radius;
z-index: dark.$zindex-popover !important;
table thead {
background: dark.$dropdown-bg;
th,
td {
color: dark.$headings-color;
&.prev,
&.next {
span {
border-color: dark.$headings-color !important;
}
}
select {
background-color: transparent;
color: dark.$headings-color;
}
}
}
&.with-week-numbers {
width: calc(#{$daterangepicker-width-with-weeks} + calc(#{dark.$dropdown-border-width} * 2));
}
&.drop-up {
margin-top: -(dark.$dropdown-spacer);
}
}
.daterangepicker .calendar-table td {
border-radius: dark.$border-radius-pill;
}
.daterangepicker .drp-selected {
font-size: dark.$font-size-sm;
}
.daterangepicker .calendar-table thead tr:last-child th {
border-radius: 0 !important;
color: dark.$headings-color;
font-size: dark.$font-size-sm;
font-weight: dark.$font-weight-normal;
}
.daterangepicker th.month {
color: dark.$headings-color;
font-weight: dark.$font-weight-normal;
}
.daterangepicker td.week,
.daterangepicker th.week {
color: dark.$headings-color;
font-weight: dark.$font-weight-normal;
}
.daterangepicker td.disabled,
.daterangepicker option.disabled {
color: dark.$text-muted;
}
.daterangepicker td.available:not(.active):hover,
.daterangepicker th.available:hover {
background-color: dark.$gray-50;
}
.daterangepicker td.off {
color: dark.$text-muted;
}
.daterangepicker .ranges li {
cursor: pointer;
padding: dark.$dropdown-item-padding-y dark.$dropdown-item-padding-x;
&:hover {
background-color: dark.$dropdown-link-hover-bg;
}
}
.daterangepicker .calendar-table .next,
.daterangepicker .calendar-table .prev {
background-color: dark.$gray-50;
span {
border-color: dark.$body-color;
}
}
.daterangepicker select {
&.hourselect,
&.minuteselect,
&.secondselect,
&.ampmselect {
background: dark.rgba-to-hex(dark.$gray-100, dark.$rgba-to-hex-bg);
border: 1px solid transparent;
font-size: dark.$font-size-sm;
color: dark.$body-color;
option {
background: dark.$card-bg;
}
}
// ! FIX: OS Windows and Linux Browsers DD Option color
&.monthselect,
&.yearselect {
option {
color: dark.$body-color;
background: dark.$card-bg;
&:disabled {
color: dark.$text-muted;
}
}
}
}
.daterangepicker .calendar-time select.disabled {
color: dark.$text-light;
}
@include dark.media-breakpoint-up(md) {
.daterangepicker {
width: auto !important;
&:not(.single) .drp-selected {
display: inline-block;
width: auto;
padding: 0;
}
}
@include app-ltr-style {
.daterangepicker:not(.single) .drp-calendar {
float: left;
&.left {
padding-right: 1rem;
}
}
}
@include app-rtl-style {
.daterangepicker:not(.single) .drp-calendar {
float: right;
&.left {
padding-left: 1rem;
}
}
}
}
@include dark.media-breakpoint-up(lg) {
.daterangepicker .ranges {
border-bottom: 0;
}
@include app-ltr-style {
.daterangepicker {
.ranges {
float: left;
}
}
}
@include app-rtl-style {
.daterangepicker {
.ranges {
float: right;
}
}
}
}
}
}

View File

@ -0,0 +1,16 @@
@import '../../scss/_bootstrap-extended/functions';
@mixin bs-select-theme($background, $color: null) {
$color: if($color, $color, color-contrast($background));
.bootstrap-select {
.dropdown-menu.inner a[aria-selected='true'] {
background: $background !important;
color: $color !important;
}
// Fix: To add focus border, .bootstrap-select adding border but not able to update as we can not have the focus on div
.dropdown-toggle.show {
border-color: $background;
}
}
}

View File

@ -0,0 +1 @@
import 'bootstrap-select/js/bootstrap-select';

View File

@ -0,0 +1,259 @@
// Bootstrap Select
// *******************************************************************************
@use '../../scss/_bootstrap-extended/include' as light;
@use '../../scss/_bootstrap-extended/include-dark' as dark;
@import '../../scss/_custom-variables/libs';
@import 'bootstrap-select/sass/bootstrap-select.scss';
// Common Styles
.bootstrap-select *,
.bootstrap-select .dropdown-toggle:focus {
outline: 0 !important;
}
.bootstrap-select {
.bs-searchbox,
.bs-actionsbox,
.bs-donebutton {
padding: 0 0 8px;
}
.dropdown-toggle {
transition: none;
padding: calc(light.$input-padding-y - light.$input-border-width) light.$input-padding-x;
box-shadow: none !important;
&.show,
&:focus {
padding: calc(light.$input-padding-y - light.$input-focus-border-width)
calc(light.$input-padding-x - light.$input-border-width);
}
&:after {
transform: rotate(45deg) translateY(-100%);
position: absolute;
inset-inline-end: 23px;
top: 50%;
margin: 0 !important;
@include app-rtl {
inset-inline-end: 12px;
}
}
&:active {
transform: none !important;
}
&.show {
&:after {
inset-inline-end: calc(23px - light.$input-border-width);
@include app-rtl {
inset-inline-end: calc(12px - light.$input-border-width);
}
}
}
.filter-option-inner-inner {
line-height: light.$input-line-height;
}
}
.btn {
&:disabled,
&.disabled {
color: light.$btn-color !important;
}
}
// For header dropdown close btn
.dropdown-menu .popover-header {
display: flex;
align-items: center;
button {
border: none;
font-size: light.$h4-font-size;
background: transparent;
padding-bottom: 0.125rem;
}
}
.is-invalid {
~ .dropdown-toggle {
&:after {
inset-inline-end: calc(23px - light.$input-border-width);
@include app-rtl {
inset-inline-end: calc(12px - light.$input-border-width);
}
}
}
}
}
.bootstrap-select.dropup {
.dropdown-toggle {
&:after {
transform: rotate(317deg) translateY(-30%);
inset-inline-end: 14px;
@include app-rtl {
inset-inline-end: calc(18px);
}
}
&.show {
&:after {
inset-inline-end: calc(14px - light.$input-border-width);
@include app-rtl {
inset-inline-end: calc(18px - light.$input-border-width);
}
}
}
}
.is-invalid {
~ .dropdown-toggle {
&:after {
inset-inline-end: calc(14px - light.$input-border-width);
@include app-rtl {
inset-inline-end: calc(18px - light.$input-border-width);
}
}
}
}
}
// Menu Position
.bootstrap-select.show-tick .dropdown-menu {
li a {
position: relative;
}
// RTL
@include app-rtl {
li a span.text {
margin-left: 2.125rem;
margin-right: 0;
}
}
.selected span.check-mark {
display: block;
right: 1rem;
top: 50%;
margin: 0;
transform: translateY(-50%);
line-height: 1;
@include app-rtl {
left: 1rem;
right: auto;
}
}
}
// To remove ripple effect
.bootstrap-select .dropdown-menu.inner .selected .waves-ripple {
display: none !important;
}
.bootstrap-select:not(.input-group-btn),
.bootstrap-select[class*='col-'] {
display: block;
}
html[class] .bootstrap-select.form-select {
background: none !important;
border: 0 !important;
padding: 0 !important;
margin: 0 !important;
}
// RTL
@include app-rtl(false) {
.bootstrap-select .dropdown-toggle .filter-option {
float: right;
right: 0;
left: auto;
text-align: right;
padding-left: inherit;
padding-right: 0;
margin-left: -100%;
margin-right: 0;
}
// Fix: Subtext rtl support
.bootstrap-select .filter-option-inner-inner {
float: right;
}
.bootstrap-select .dropdown-menu li small.text-muted,
.bootstrap-select .filter-option small.text-muted {
position: relative;
top: 2px;
padding-left: 0;
padding-right: 0.5em;
float: left;
}
.bootstrap-select .dropdown-toggle .filter-option-inner {
padding-left: inherit;
padding-right: 0;
}
}
// Light style
@if $enable-light-style {
.light-style {
.bootstrap-select {
background-color: light.$input-bg;
.dropdown-toggle {
border-radius: light.$border-radius;
border: light.$input-border-width solid light.$input-border-color;
&.show,
&:focus {
border: light.$input-focus-border-width solid light.$primary;
}
&:not(.show):hover {
border-color: light.$input-border-hover-color;
}
}
.dropdown-menu {
&[data-popper-placement='top-start'],
&[data-popper-placement='top-end'] {
box-shadow: 0 -0.2rem 1.25rem rgba(light.rgba-to-hex(light.$gray-500, light.$rgba-to-hex-bg), 0.4);
}
.notify {
background: light.$popover-bg;
border: light.$input-border-width solid light.$popover-border-color;
}
.popover-header button {
color: light.$body-color;
}
}
}
}
}
// Dark Style
@if $enable-dark-style {
.dark-style {
.bootstrap-select {
background-color: dark.$input-bg;
.dropdown-toggle {
color: dark.$input-color;
&:hover {
color: dark.$input-color;
}
border: dark.$input-border-width solid dark.$input-border-color;
border-radius: dark.$border-radius;
&.show,
&:focus {
border: dark.$input-focus-border-width solid dark.$primary;
}
&:not(.show):hover {
border-color: dark.$input-border-hover-color;
}
}
.dropdown-menu {
&[data-popper-placement='top-start'],
&[data-popper-placement='top-end'] {
box-shadow: 0 -0.2rem 1.25rem rgba(15, 20, 34, 0.55);
}
.notify {
background: dark.$popover-bg;
border: dark.$input-border-width solid dark.$popover-border-color;
}
.popover-header button {
color: dark.$body-color;
}
}
}
}
}

View File

@ -0,0 +1,9 @@
import 'bootstrap-table';
import('bootstrap-table/dist/extensions/cookie/bootstrap-table-cookie.js')
import 'bootstrap-table/dist/extensions/export/bootstrap-table-export.js';
import 'bootstrap-table/dist/extensions/fixed-columns/bootstrap-table-fixed-columns.js';
import 'bootstrap-table/dist/extensions/mobile/bootstrap-table-mobile.js';
import 'bootstrap-table/dist/locale/bootstrap-table-es-MX.js';
import * as XLSX from 'xlsx';
window.XLSX = XLSX;

View File

@ -0,0 +1,2 @@
@import 'bootstrap-table/dist/bootstrap-table.css';
@import 'bootstrap-table/dist/extensions/fixed-columns/bootstrap-table-fixed-columns.css';

View File

@ -0,0 +1,51 @@
// Stepper Mixin
// *******************************************************************************
@mixin bs-stepper-theme($background) {
$color: color-contrast($background);
.bs-stepper {
.step {
&.active {
.bs-stepper-circle {
background-color: $background;
color: $color;
box-shadow: 0 0.125rem 0.375rem 0 rgba($background, 0.3);
}
.bs-stepper-icon svg {
fill: $background !important;
}
.bs-stepper-icon i,
.bs-stepper-label {
color: $background !important;
}
}
&.crossed {
.step-trigger {
.bs-stepper-circle {
background-color: rgba-to-hex(rgba($background, 0.16), $card-bg) !important;
color: $background !important;
}
.bs-stepper-icon svg {
fill: $background !important;
}
.bs-stepper-icon i {
color: $background !important;
}
}
}
}
&.wizard-icons {
.step.crossed {
.bs-stepper-label {
color: $background !important;
}
& + {
.line {
i {
color: $background;
}
}
}
}
}
}
}

View File

@ -0,0 +1,37 @@
import Stepper from 'bs-stepper/dist/js/bs-stepper';
const bsStepper = document.querySelectorAll('.bs-stepper');
// Adds crossed class
bsStepper.forEach(el => {
el.addEventListener('show.bs-stepper', function (event) {
var index = event.detail.indexStep;
var numberOfSteps = el.querySelectorAll('.line').length;
var line = el.querySelectorAll('.step');
// The first for loop is for increasing the steps,
// the second is for turning them off when going back
// and the third with the if statement because the last line
// can't seem to turn off when I press the first item. ¯\_(ツ)_/¯
for (let i = 0; i < index; i++) {
line[i].classList.add('crossed');
for (let j = index; j < numberOfSteps; j++) {
line[j].classList.remove('crossed');
}
}
if (event.detail.to == 0) {
for (let k = index; k < numberOfSteps; k++) {
line[k].classList.remove('crossed');
}
line[0].classList.remove('crossed');
}
});
});
try {
window.Stepper = Stepper;
} catch (e) {}
export { Stepper };

View File

@ -0,0 +1,549 @@
@use '../../scss/_bootstrap-extended/include' as light;
@use '../../scss/_bootstrap-extended/include-dark' as dark;
@import 'bs-stepper/dist/css/bs-stepper';
@import '../../scss/_custom-variables/libs';
$bs-stepper-header-padding-y: 1.5rem !default;
$bs-stepper-header-padding-x: $bs-stepper-header-padding-y !default;
$bs-stepper-content-padding-x: 1.5rem !default;
$bs-stepper-content-padding-y: $bs-stepper-content-padding-x !default;
$bs-stepper-trigger-padding: 1.25rem !default;
$bs-stepper-trigger-padding-vertical: 0.6rem !default;
$bs-stepper-label-max-width: 224px !default;
$bs-stepper-svg-icon-height: 3.75rem !default;
$bs-stepper-svg-icon-width: 3.75rem !default;
$bs-stepper-icon-font-size: 1.6rem !default;
$bs-stepper-vertical-separator-height: 1.55rem !default;
$bs-stepper-vertical-header-min-width: 18rem !default;
// Default Styles
.bs-stepper {
border-radius: light.$border-radius;
.line {
flex: 0;
min-width: auto;
min-height: auto;
background-color: transparent;
margin: 0;
}
.bs-stepper-header {
padding: $bs-stepper-header-padding-y $bs-stepper-header-padding-x;
.step {
.step-trigger {
padding: 0;
flex-wrap: nowrap;
gap: 0.5rem;
font-weight: light.$font-weight-medium;
.bs-stepper-label {
margin: 0;
max-width: $bs-stepper-label-max-width;
overflow: hidden;
text-overflow: ellipsis;
text-align: start;
display: inline-grid;
font-weight: light.$font-weight-medium;
font-size: light.$font-size-base;
line-height: light.$h6-line-height;
.bs-stepper-title {
font-weight: light.$font-weight-medium;
}
.bs-stepper-subtitle {
font-size: light.$small-font-size;
font-weight: light.$font-weight-base;
}
}
&:hover {
background-color: transparent;
}
@include light.media-breakpoint-down(lg) {
padding: calc($bs-stepper-trigger-padding * 0.5) 0;
}
}
.bs-stepper-circle {
display: flex;
align-items: center;
justify-content: center;
border-radius: light.$border-radius;
width: 2.375rem;
height: 2.375rem;
font-size: light.$h5-font-size;
font-weight: light.$font-weight-medium;
i {
font-size: 1.375rem;
}
}
}
}
.bs-stepper-content {
padding: $bs-stepper-content-padding-y $bs-stepper-content-padding-x;
}
&.vertical {
.bs-stepper-header {
min-width: $bs-stepper-vertical-header-min-width;
.step {
.step-trigger {
padding: $bs-stepper-trigger-padding-vertical 0;
}
&:first-child {
.step-trigger {
padding-top: 0;
}
}
&:last-child {
.step-trigger {
padding-bottom: 0;
}
}
}
.line {
position: relative;
min-height: 1px;
}
}
.bs-stepper-content {
width: 100%;
.content {
&:not(.active) {
display: none;
}
}
}
&.wizard-icons {
.step {
text-align: center;
padding: 0.75rem 0;
}
}
}
&.wizard-icons {
.bs-stepper-header {
justify-content: center;
.step-trigger {
padding: $bs-stepper-trigger-padding;
flex-direction: column;
gap: 0.5rem;
.bs-stepper-icon {
svg {
height: $bs-stepper-svg-icon-height;
width: $bs-stepper-svg-icon-width;
}
i {
font-size: $bs-stepper-icon-font-size;
}
}
}
@include light.media-breakpoint-up(lg) {
justify-content: space-around;
gap: 1rem;
}
}
}
// Remove borders from wizard modern
&.wizard-modern {
.bs-stepper-header {
border-bottom: none !important;
}
.bs-stepper-content {
border-radius: light.$border-radius;
}
&.vertical {
.bs-stepper-header {
border-right: none !important;
}
}
}
&:not(.vertical):not(.wizard-icons) .bs-stepper-header {
@include light.media-breakpoint-up(lg) {
gap: 1.25rem;
}
}
}
@include app-rtl(false) {
.bs-stepper.wizard-icons .bs-stepper-header .step-trigger {
@include light.media-breakpoint-down(lg) {
padding-right: 0;
}
}
}
@include app-ltr(false) {
.bs-stepper.wizard-icons .bs-stepper-header .step-trigger {
@include light.media-breakpoint-down(lg) {
padding-left: 0;
}
}
}
// Styles for Modal example Create App wizard
#wizard-create-app {
&.vertical {
.bs-stepper-header {
min-width: $bs-stepper-vertical-header-min-width - 3;
}
}
}
// Light style
@if $enable-light-style {
.light-style {
.bs-stepper {
background-color: light.$card-bg;
&:not(.wizard-modern) {
box-shadow: light.$card-box-shadow;
}
.bs-stepper-header {
border-bottom: 1px solid light.$border-color;
.line {
i {
color: light.$body-color;
}
}
.bs-stepper-title,
.bs-stepper-label {
color: light.$headings-color;
}
.bs-stepper-label {
.bs-stepper-subtitle {
color: light.$body-color;
}
}
.step {
&:not(.active) {
.bs-stepper-circle {
background-color: light.$gray-50;
color: light.$headings-color;
}
}
&.crossed .step-trigger {
.bs-stepper-label .bs-stepper-subtitle,
.bs-stepper-title {
color: light.$text-muted;
}
}
}
}
.step-trigger:focus {
color: light.$headings-color;
}
&.vertical {
.bs-stepper-header {
border-bottom: none;
@include light.media-breakpoint-down(lg) {
border-right: none !important;
border-left: none !important;
border-bottom: 1px solid light.$border-color;
}
}
}
&.wizard-modern {
background-color: transparent;
.bs-stepper-content {
background-color: light.$card-bg;
box-shadow: light.$card-box-shadow;
}
}
&.wizard-icons {
.bs-stepper-header {
.bs-stepper-icon {
svg {
fill: light.$headings-color;
}
i {
fill: light.$headings-color;
}
}
.bs-stepper-label {
color: light.$headings-color;
}
}
}
}
}
// ! FIX: Vertical border issue in rtl and ltr
@include app-rtl(false) {
.light-style {
.bs-stepper {
&.vertical {
.bs-stepper-header {
border-left: 1px solid light.$border-color;
}
}
}
}
}
@include app-ltr(false) {
.light-style {
.bs-stepper {
&.vertical {
.bs-stepper-header {
border-right: 1px solid light.$border-color;
}
}
}
}
}
}
// Dark Style
@if $enable-dark-style {
.dark-style {
.bs-stepper {
background-color: dark.$card-bg;
.bs-stepper-header {
border-bottom: 1px solid dark.$border-color;
.line {
i {
color: dark.$body-color;
}
}
.bs-stepper-label,
.bs-stepper-title {
color: dark.$headings-color;
}
.bs-stepper-label {
.bs-stepper-subtitle {
color: dark.$body-color;
}
}
.step {
&:not(.active) {
.bs-stepper-circle {
background-color: dark.$gray-50;
color: dark.$headings-color;
}
}
&.crossed .step-trigger {
.bs-stepper-label .bs-stepper-subtitle,
.bs-stepper-title {
color: dark.$text-muted;
}
}
}
}
.step-trigger:focus {
color: dark.$headings-color;
}
&.vertical {
.bs-stepper-header {
border-bottom: none;
@include light.media-breakpoint-down(lg) {
border-right: none !important;
border-left: none !important;
border-bottom: 1px solid dark.$border-color;
}
}
}
&.wizard-modern {
background-color: transparent;
.bs-stepper-content {
background-color: dark.$card-bg;
box-shadow: dark.$card-box-shadow;
}
}
&.wizard-icons {
.bs-stepper-header {
.bs-stepper-icon {
i {
color: dark.$headings-color;
}
svg {
fill: dark.$headings-color;
}
}
.bs-stepper-label {
color: dark.$headings-color;
}
}
}
}
}
// ! FIX: Vertical border issue in rtl and ltr
@include app-rtl(false) {
.dark-style {
.bs-stepper {
&.vertical {
.bs-stepper-header {
border-left: 1px solid dark.$border-color;
}
}
}
}
}
@include app-ltr(false) {
.dark-style {
.bs-stepper {
&.vertical {
.bs-stepper-header {
border-right: 1px solid dark.$border-color;
}
}
}
}
}
}
// RTL
@include app-rtl(false) {
.bs-stepper {
.bs-stepper-content {
.btn-next:not(.btn-submit),
.btn-prev {
i {
transform: rotate(180deg);
}
}
}
&.vertical {
&.wizard-icons {
.bs-stepper-header {
.line:before {
right: 50%;
}
}
}
}
// Remove borders from wizard modern
&.wizard-modern {
&.vertical {
.bs-stepper-header {
border-left: none !important;
}
}
}
@include light.media-breakpoint-up(lg) {
.bs-stepper-header {
.line {
i {
transform: rotate(180deg);
}
}
}
}
@include light.media-breakpoint-down(lg) {
.bs-stepper-header {
.step {
.step-trigger {
.bs-stepper-label {
margin-left: 0;
margin-right: 1rem;
}
}
}
}
&.wizard-icons {
.bs-stepper-header {
.line {
&:before {
margin-right: 0.75rem;
}
}
}
}
}
}
}
// Media Queries
@include light.media-breakpoint-down(lg) {
.bs-stepper {
.bs-stepper-header {
flex-direction: column;
align-items: flex-start;
.step {
.step-trigger {
flex-direction: row;
.bs-stepper-label {
margin-left: 0.35rem;
}
}
&:first-child {
.step-trigger {
padding-top: 0;
}
}
&:last-child {
.step-trigger {
padding-bottom: 0;
}
}
}
}
&.vertical {
flex-direction: column;
.bs-stepper-header {
align-items: flex-start;
}
&.wizard-icons {
.bs-stepper-header {
.line:before {
left: 0.75rem;
margin-left: 0;
}
}
}
}
&:not(.vertical) {
.bs-stepper-header {
.line {
i {
display: none;
}
}
}
}
&.wizard-icons {
.bs-stepper-header .step:not(:first-child) {
.bs-stepper-icon {
svg {
margin-top: 0.5rem;
}
}
}
}
}
}
@media (max-width: 520px) {
.bs-stepper-header {
margin: 0;
}
}
// Styles for Create App Modal Wizard
#wizard-create-app {
&.vertical {
.bs-stepper-header {
min-width: $bs-stepper-vertical-header-min-width - 3;
}
}
}

View File

@ -0,0 +1 @@
import 'cleave.js/dist/addons/cleave-phone.us';

View File

@ -0,0 +1 @@
import 'cleave.js/dist/cleave';

View File

@ -0,0 +1,28 @@
import JSZip from 'jszip';
import pdfMake from 'pdfmake';
import 'pdfmake/build/vfs_fonts';
import 'datatables.net-bs5';
import 'datatables.net-fixedcolumns-bs5';
import 'datatables.net-fixedheader-bs5';
import 'datatables.net-select-bs5';
import 'datatables.net-buttons';
import 'datatables.net-buttons-bs5';
import 'datatables.net-buttons/js/buttons.html5';
import 'datatables.net-buttons/js/buttons.print';
import 'datatables.net-responsive';
import 'datatables.net-responsive-bs5';
import 'datatables.net-rowgroup-bs5';
import Checkbox from 'jquery-datatables-checkboxes';
// This solution related to font issues with pdfMake
pdfMake.fonts = {
Roboto: {
normal: 'https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.66/fonts/Roboto/Roboto-Regular.ttf',
bold: 'https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.66/fonts/Roboto/Roboto-Medium.ttf',
italics: 'https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.66/fonts/Roboto/Roboto-Italic.ttf',
bolditalics: 'https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.66/fonts/Roboto/Roboto-MediumItalic.ttf'
}
};
$.fn.dataTable.ext.Checkbox = Checkbox(window, $);
$.fn.dataTable.ext.buttons.pdfMake = pdfMake;
window.JSZip = JSZip;

View File

@ -0,0 +1,394 @@
@use '../../scss/_bootstrap-extended/include' as light;
@use '../../scss/_bootstrap-extended/include-dark' as dark;
@import '../../scss/_custom-variables/libs';
@import 'datatables.net-bs5/css/dataTables.bootstrap5';
// Margin between select, input field and text
div.dataTables_wrapper div.dataTables_length select {
margin-left: 0.5rem;
margin-right: 0.5rem;
}
div.dataTables_wrapper div.dataTables_filter input {
margin-left: 1em;
}
.dataTable .emp_name {
font-weight: light.$font-weight-medium;
}
// Shadow none for action buttons
.dataTable td .btn {
box-shadow: none !important;
}
// Card header inside the datatable
div.dataTables_wrapper .card-header {
display: flex;
align-items: center;
justify-content: space-between;
}
div.dataTables_wrapper div.dataTables_info {
padding-top: light.$spacer * 0.5;
}
table.table-bordered.dataTable {
// For complex header and column search datatable
&.dt-complex-header,
&.dt-column-search {
thead tr th {
border-width: 1px;
}
tfoot tr th {
border-width: 1px;
}
}
& tfoot tr th {
border-bottom-width: 1px;
}
& > :not(caption) > * {
& > * {
border-width: 0;
}
}
}
// Remove left and right border from datatable with table-bordered class
table.table-bordered.dataTable {
tr:first-child th,
td {
&:first-child {
@include app-ltr() {
border-left-width: 0;
}
@include app-rtl() {
border-right-width: 0;
}
}
&:last-child {
@include app-ltr() {
border-right-width: 0;
}
@include app-rtl() {
border-left-width: 0;
}
}
}
> tbody:not(caption) tr:first-child {
border-top-width: 0;
}
}
// Responsive datatable in desktop screen
@media screen and (min-width: 1399.98px) {
table.table-responsive {
display: table;
}
}
// RTL style
@include app-rtl(false) {
div.dataTables_wrapper .dataTables_filter {
display: flex;
justify-content: flex-end;
input {
margin-left: 0;
margin-right: 1rem;
}
}
table.table-bordered.dataTable th,
table.table-bordered.dataTable td {
border-right-width: 0;
border-left-width: 1px;
&:last-child {
border-left-width: 0;
}
}
}
table.dataTable {
width: 100% !important;
border-collapse: collapse !important;
margin-bottom: light.$spacer !important;
margin-top: 0 !important;
thead th {
&.sorting_disabled {
&::before,
&::after {
display: none !important;
}
}
&.sorting {
&:before,
&:after {
visibility: hidden;
}
&:hover {
&:before,
&:after {
visibility: visible;
}
}
}
}
@include app-rtl {
&.table-sm > thead > tr > th {
padding-left: 1.25rem;
}
&.table-sm .sorting:before,
&.table-sm .sorting_asc:before,
&.table-sm .sorting_desc:before {
right: auto !important;
left: 0.85em !important;
}
thead th,
thead td,
tfoot th,
tfoot td {
text-align: right;
}
}
// Checkbox height & width for datatables checkboxes
.form-check-input {
width: light.$form-datatables-check-input-size;
height: light.$form-datatables-check-input-size;
}
}
// to add spacing between table and datatable footer elements like pagination & info
.dataTables_scroll {
margin-bottom: 0.75rem;
}
// Used while complex headers
table.dataTable thead th {
vertical-align: middle;
}
table.dataTable thead .sorting,
table.dataTable thead .sorting_asc,
table.dataTable thead .sorting_desc,
table.dataTable thead .sorting_asc_disabled,
table.dataTable thead .sorting_desc_disabled {
&::before,
&::after {
line-height: 1.25rem !important;
font-family: tabler-icons !important;
font-size: 1rem !important;
width: 10px;
height: 10px;
right: 0.78rem !important;
}
&::before {
content: '\ea62' !important;
top: 0.58rem !important;
}
&::after {
bottom: 0.72rem !important;
content: '\ea5f' !important;
}
@include app-rtl {
&::before {
right: auto !important;
left: 0.58em !important;
}
&::after {
right: auto !important;
left: 0.58em !important;
}
}
}
// DataTable within card
div.card-datatable.dataTable,
div.card-datatable .dataTable {
border-right: 0;
border-left: 0;
}
// Card header inside the datatable
@media screen and (max-width: 575.98px) {
div.dataTables_wrapper .card-header {
display: block;
}
.dtr-bs-modal.modal {
// padding-left: 0.75rem;
.modal-body {
padding: 0;
overflow: auto;
}
}
.dataTable_select div.dataTables_wrapper div.dataTables_info {
flex-direction: column;
}
}
@media screen and (max-width: 767.98px) {
div.dataTables_wrapper div.dataTables_info {
padding-bottom: light.$table-cell-padding-y;
}
}
div.dataTables_wrapper {
div.dataTables_length,
.dataTables_filter {
margin-top: light.$spacer * 1.5;
margin-bottom: light.$spacer * 1.5;
}
}
// common style for light / dark
div.dataTables_wrapper div.dataTables_paginate ul.pagination {
.page-item {
&,
&.next,
&.previous,
&.first,
&.last {
.page-link {
border-radius: light.$border-radius;
}
}
}
}
div.dataTables_wrapper div.dataTables_paginate ul.pagination .page-link {
div:not(.table-responsive) div.dataTables_wrapper .dataTables_paginate {
margin-right: 0;
}
}
@include light.media-breakpoint-down(md) {
div.dataTables_wrapper div.dataTables_length label,
div.dataTables_wrapper div.dataTables_filter label,
div.dataTables_wrapper div.dataTables_info,
div.dataTables_wrapper div.dataTables_paginate {
justify-content: center;
}
}
@include light.media-breakpoint-down(sm) {
div.dataTables_wrapper div.dataTables_paginate ul.pagination {
justify-content: start !important;
overflow-x: scroll;
}
}
// DataTable within card
div.card-datatable {
padding-bottom: light.$card-spacer-x-sm; // Check this in site and update if needed
[class*='col-md-'] {
padding-right: light.$table-cell-padding-x !important;
padding-left: light.$table-cell-padding-x !important;
}
// length, filter & info, pagination row margin
&:not(.table-responsive) .dataTables_wrapper .row {
&:first-child,
&:last-child {
margin: 0;
}
}
}
// LTR style
@include app-ltr(false) {
div.card-datatable table.dataTable thead th,
div.card-datatable table.dataTable tfoot th {
&:first-child {
padding-left: light.$card-spacer-x;
padding-right: light.$card-spacer-x;
}
&:last-child {
padding-right: light.$card-spacer-x-sm;
}
}
div.card-datatable table.dataTable tbody td {
&:first-child {
padding-left: light.$card-spacer-x;
padding-right: light.$card-spacer-x;
}
}
}
// RTL Style
@include app-rtl(false) {
table.dataTable.table-sm > thead > tr > th {
padding-right: light.$table-cell-padding-x-sm;
}
table.table-bordered.dataTable tr {
td,
th,
th:first-child {
border-left-width: 0 !important;
}
}
table.dataTable {
thead th,
tbody td,
tfoot th {
padding-right: light.$table-cell-padding-x;
}
&.table-sm thead th,
&.table-sm tbody td,
&.table-sm tfoot th {
padding-right: light.$table-cell-padding-x-sm;
}
}
div.card-datatable table.dataTable {
thead th,
tbody td,
tfoot th {
&:first-child {
padding-right: light.$card-spacer-x;
}
&:last-child {
padding-left: light.$card-spacer-x;
}
}
}
}
// Light style
@if $enable-light-style {
.light-style {
div.dataTables_wrapper div.dataTables_info {
color: light.$text-muted;
}
div.dataTables_scrollBody table {
border-top-color: light.$table-border-color;
}
table.dataTable th,
table.dataTable td {
border-color: light.$table-border-color !important;
}
}
}
// Dark Style
@if $enable-dark-style {
.dark-style {
div.dataTables_wrapper div.dataTables_info {
color: dark.$text-muted;
}
div.dataTables_scrollBody table {
border-top-color: dark.$table-border-color;
}
table.dataTable th,
table.dataTable td {
border-color: dark.$table-border-color !important;
}
}
}

View File

@ -0,0 +1,101 @@
@use '../../scss/_bootstrap-extended/include' as light;
@use '../../scss/_bootstrap-extended/include-dark' as dark;
@import '../../scss/_custom-variables/libs';
@import 'datatables.net-buttons-bs5/css/buttons.bootstrap5';
// remove 0.5em margin bottom from dt-buttons
@media screen and (max-width: 767px) {
div.dt-buttons {
margin-bottom: 0;
}
}
div.dataTables_wrapper .dt-button-collection {
border: 0;
border-radius: light.$dropdown-border-radius;
padding: light.$dropdown-padding-y light.$dropdown-padding-x;
width: auto;
> div[role='menu'] {
text-align: left;
}
}
// avoid dropdown to overlap the trigger button
.dt-button-collection {
margin-top: 0.2rem;
}
div.dropdown-menu.dt-button-collection,
div.dt-button-collection .dt-button:not(.dt-btn-split-drop) {
min-width: 8rem;
}
.dt-down-arrow {
display: none;
}
// override button radius
div.dt-button-collection .dt-button,
div.dt-buttons div.dropdown-menu .dt-button {
border-radius: light.$dropdown-border-radius;
}
// Light style
@if $enable-light-style {
.light-style {
div.dataTables_wrapper .dt-button-collection {
background-color: light.$dropdown-bg;
}
.dataTable a:not([href]):not([tabindex]) {
color: map-get(light.$theme-colors, success);
}
.dt-button-info {
box-shadow: light.$floating-component-shadow;
}
.dt-button-collection {
.dropdown-item {
padding: light.$dropdown-item-padding-y light.$dropdown-item-padding-x;
}
}
}
}
// Dark style
@if $enable-dark-style {
.dark-style {
div.dataTables_wrapper .dt-button-collection {
background-color: dark.$dropdown-bg;
}
.dataTable a:not([href]):not([tabindex]) {
color: map-get(dark.$theme-colors, success);
}
.dt-button-info {
box-shadow: dark.$floating-component-shadow;
}
.dt-button-collection {
.dropdown-item {
padding: dark.$dropdown-item-padding-y dark.$dropdown-item-padding-x;
}
}
}
}
.dt-button-info {
border-width: 0 !important;
border-radius: light.$border-radius !important;
h2 {
font-size: light.$h4-font-size !important;
}
}
.dt-buttons {
position: relative;
.dt-button-collection .dropdown-item {
@include app-rtl {
text-align: right;
}
}
&.btn-group {
button {
border-color: transparent !important;
border-radius: light.$border-radius !important;
}
}
}
div.dt-buttons .dropdown-menu .dt-button {
border-radius: light.$border-radius;
}

View File

@ -0,0 +1,2 @@
@import '../../scss/_custom-variables/libs';
@import 'jquery-datatables-checkboxes/css/dataTables.checkboxes';

View File

@ -0,0 +1,133 @@
@use '../../scss/_bootstrap-extended/include' as light;
@use '../../scss/_bootstrap-extended/include-dark' as dark;
@import '../../scss/_custom-variables/libs';
@import 'datatables.net-fixedcolumns-bs5/css/fixedColumns.bootstrap5';
// Fixed column style
div.dataTables_scrollBody thead tr,
div.DTFC_LeftBodyLiner thead tr {
border-top-width: 0;
border-bottom-width: 0;
}
div.dataTables_scrollBody {
border: 0 !important;
}
@include app-ltr(false) {
div.dataTables_scrollFootInner table.table-bordered tr th:first-child,
div.dataTables_scrollHeadInner table.table-bordered tr th:first-child {
border-left: 0 !important;
}
}
@include app-rtl(false) {
table.dataTable thead th,
table.dataTable thead td,
table.dataTable tfoot th,
table.dataTable tfoot td {
text-align: right !important;
}
}
// Light style
@if $enable-light-style {
.light-style {
table.DTFC_Cloned tr {
border-color: light.$table-border-color;
}
// fixed header and footer border
div.dataTables_scrollFootInner table.table-bordered tr th:first-child,
div.dataTables_scrollHeadInner table.table-bordered tr th:first-child {
border-left: 1px solid light.$table-border-color;
}
// fixed column background color
table.dataTable thead tr > .dtfc-fixed-left,
table.dataTable thead tr > .dtfc-fixed-right,
table.dataTable tbody tr > .dtfc-fixed-left,
table.dataTable tbody tr > .dtfc-fixed-right,
div.dtfc-right-top-blocker,
div.dtfc-left-top-blocker {
background-color: light.$card-bg;
margin-top: 1px !important;
height: 0px !important;
}
// To override BS5 css
.dt-fixedcolumns thead {
border-top-color: light.$table-border-color;
}
&[dir='rtl'] {
div.dataTables_scrollHead,
div.dataTables_scrollBody {
table {
border-width: 0;
}
}
div.DTFC_LeftBodyLiner {
padding-right: 0 !important;
}
div.DTFC_RightHeadWrapper,
div.DTFC_RightBodyWrapper {
table {
border: 0;
}
}
div.DTFC_RightBodyLiner {
padding-left: 0 !important;
}
}
}
}
// Dark style
@if $enable-dark-style {
.dark-style {
table.DTFC_Cloned tr {
background-color: dark.$card-bg;
border-color: dark.$table-border-color;
}
div.dataTables_scrollHead table,
div.DTFC_RightHeadWrapper table,
table.dataTable.fixedHeader-floating,
table.dataTable.fixedHeader-locked {
background-color: dark.$card-bg;
}
// fixed header and footer border
div.dataTables_scrollFootInner table.table-bordered tr th:first-child,
div.dataTables_scrollHeadInner table.table-bordered tr th:first-child {
border-left: 1px solid dark.$table-border-color !important;
}
// fixed column background color
table.dataTable thead tr > .dtfc-fixed-left,
table.dataTable thead tr > .dtfc-fixed-right,
table.dataTable tbody tr > .dtfc-fixed-left,
table.dataTable tbody tr > .dtfc-fixed-right,
div.dtfc-right-top-blocker,
div.dtfc-left-top-blocker {
background-color: dark.$card-bg;
margin-top: 1px !important;
height: 0px !important;
}
// To override BS5 css
.dt-fixedcolumns thead {
border-top-color: dark.$table-border-color;
}
&[dir='rtl'] {
div.dataTables_scrollHead,
div.dataTables_scrollBody {
table {
border-width: 0;
}
}
div.DTFC_LeftBodyLiner {
padding-right: 0 !important;
}
div.DTFC_RightHeadWrapper,
div.DTFC_RightBodyWrapper {
table {
border: 0;
}
}
div.DTFC_RightBodyLiner {
padding-left: 0 !important;
}
}
}
}

View File

@ -0,0 +1,40 @@
@use '../../scss/_bootstrap-extended/include' as light;
@use '../../scss/_bootstrap-extended/include-dark' as dark;
@import '../../scss/_custom-variables/libs';
@import 'datatables.net-fixedheader-bs5/css/fixedHeader.bootstrap5';
// Fixed header Style
.dt-fixedheader.fixedHeader-floating.table.dataTable {
width: auto !important;
}
.dt-fixedheader.fixedHeader-locked.table.dataTable {
display: none;
}
// Last style
@if $enable-light-style {
.light-style {
.dtfh-floatingparenthead {
border-bottom: 1px solid light.$table-border-color;
}
.table-bordered.dt-fixedheader.fixedHeader-floating.table.dataTable thead > tr > th,
.table-bordered.dt-fixedheader.fixedHeader-locked.table.dataTable thead > tr > th {
border-bottom-width: 1px;
border-color: light.$table-border-color;
}
}
}
// Dark style
@if $enable-dark-style {
.dark-style {
.dtfh-floatingparenthead {
border-bottom: 1px solid dark.$table-border-color;
}
.table-bordered.dt-fixedheader.fixedHeader-floating.table.dataTable thead > tr > th,
.table-bordered.dt-fixedheader.fixedHeader-locked.table.dataTable thead > tr > th {
border-bottom-width: 1px;
border-color: dark.$table-border-color;
}
}
}

View File

@ -0,0 +1,195 @@
export const datatable_spanish_default = {
processing: 'Procesando...',
lengthMenu: 'Mostrar _MENU_ registros',
zeroRecords: 'No se encontraron resultados',
emptyTable: 'Ningún dato disponible en esta tabla',
infoEmpty: 'Mostrando registros del 0 al 0 de un total de 0 registros',
infoFiltered: '(filtrado de un total de _MAX_ registros)',
search: 'Buscar:',
infoThousands: ',',
loadingRecords: 'Cargando...',
paginate: {
first: 'Primero',
last: 'Último',
next: 'Siguiente',
previous: 'Anterior'
},
aria: {
sortAscending: ': Activar para ordenar la columna de manera ascendente',
sortDescending: ': Activar para ordenar la columna de manera descendente'
},
buttons: {
copy: 'Copiar',
colvis: 'Visibilidad',
collection: 'Colección',
colvisRestore: 'Restaurar visibilidad',
copyKeys:
'Presione ctrl o u2318 + C para copiar los datos de la tabla al portapapeles del sistema. <br /> <br /> Para cancelar, haga clic en este mensaje o presione escape.',
copySuccess: {
1: 'Copiada 1 fila al portapapeles',
_: 'Copiadas %d fila al portapapeles'
},
copyTitle: 'Copiar al portapapeles',
csv: 'CSV',
excel: 'Excel',
pageLength: {
'-1': 'Mostrar todas las filas',
_: 'Mostrar %d filas'
},
pdf: 'PDF',
print: 'Imprimir'
},
autoFill: {
cancel: 'Cancelar',
fill: 'Rellene todas las celdas con <i>%d</i>',
fillHorizontal: 'Rellenar celdas horizontalmente',
fillVertical: 'Rellenar celdas verticalmentemente'
},
decimal: ',',
searchBuilder: {
add: 'Añadir condición',
button: {
0: 'Constructor de búsqueda',
_: 'Constructor de búsqueda (%d)'
},
clearAll: 'Borrar todo',
condition: 'Condición',
conditions: {
date: {
after: 'Despues',
before: 'Antes',
between: 'Entre',
empty: 'Vacío',
equals: 'Igual a',
notBetween: 'No entre',
notEmpty: 'No Vacio',
not: 'Diferente de'
},
number: {
between: 'Entre',
empty: 'Vacio',
equals: 'Igual a',
gt: 'Mayor a',
gte: 'Mayor o igual a',
lt: 'Menor que',
lte: 'Menor o igual que',
notBetween: 'No entre',
notEmpty: 'No vacío',
not: 'Diferente de'
},
string: {
contains: 'Contiene',
empty: 'Vacío',
endsWith: 'Termina en',
equals: 'Igual a',
notEmpty: 'No Vacio',
startsWith: 'Empieza con',
not: 'Diferente de'
},
array: {
not: 'Diferente de',
equals: 'Igual',
empty: 'Vacío',
contains: 'Contiene',
notEmpty: 'No Vacío',
without: 'Sin'
}
},
data: 'Data',
deleteTitle: 'Eliminar regla de filtrado',
leftTitle: 'Criterios anulados',
logicAnd: 'Y',
logicOr: 'O',
rightTitle: 'Criterios de sangría',
title: {
0: 'Constructor de búsqueda',
_: 'Constructor de búsqueda (%d)'
},
value: 'Valor'
},
searchPanes: {
clearMessage: 'Borrar todo',
collapse: {
0: 'Paneles de búsqueda',
_: 'Paneles de búsqueda (%d)'
},
count: '{total}',
countFiltered: '{shown} ({total})',
emptyPanes: 'Sin paneles de búsqueda',
loadMessage: 'Cargando paneles de búsqueda',
title: 'Filtros Activos - %d'
},
select: {
cells: {
1: '1 celda seleccionada',
_: '%d celdas seleccionadas'
},
columns: {
1: '1 columna seleccionada',
_: '%d columnas seleccionadas'
},
rows: {
1: '1 fila seleccionada',
_: '%d filas seleccionadas'
}
},
thousands: '.',
datetime: {
previous: 'Anterior',
next: 'Proximo',
hours: 'Horas',
minutes: 'Minutos',
seconds: 'Segundos',
unknown: '-',
amPm: ['AM', 'PM'],
months: {
0: 'Enero',
1: 'Febrero',
10: 'Noviembre',
11: 'Diciembre',
2: 'Marzo',
3: 'Abril',
4: 'Mayo',
5: 'Junio',
6: 'Julio',
7: 'Agosto',
8: 'Septiembre',
9: 'Octubre'
},
weekdays: ['Dom', 'Lun', 'Mar', 'Mie', 'Jue', 'Vie', 'Sab']
},
editor: {
close: 'Cerrar',
create: {
button: 'Nuevo',
title: 'Crear Nuevo Registro',
submit: 'Crear'
},
edit: {
button: 'Editar',
title: 'Editar Registro',
submit: 'Actualizar'
},
remove: {
button: 'Eliminar',
title: 'Eliminar Registro',
submit: 'Eliminar',
confirm: {
_: '¿Está seguro que desea eliminar %d filas?',
1: '¿Está seguro que desea eliminar 1 fila?'
}
},
error: {
system: 'Ha ocurrido un error en el sistema (<a target="\\" rel="\\ nofollow" href="\\">Más información&lt;\\/a&gt;).</a>'
},
multi: {
title: 'Múltiples Valores',
info: 'Los elementos seleccionados contienen diferentes valores para este registro. Para editar y establecer todos los elementos de este registro con el mismo valor, hacer click o tap aquí, de lo contrario conservarán sus valores individuales.',
restore: 'Deshacer Cambios',
noMulti: 'Este registro puede ser editado individualmente, pero no como parte de un grupo.'
}
},
info: 'Mostrando _START_ a _END_ de _TOTAL_ registros',
search: '',
searchPlaceholder: 'Buscar'
};

View File

@ -0,0 +1,9 @@
@mixin bs-datatables-theme($background) {
// Style for responsive icon
table.dataTable.dtr-column > tbody > tr > td.control:before,
table.dataTable.dtr-column > tbody > tr > th.control:before {
background-color: $background;
border: 2px solid $rgba-to-hex-bg;
box-shadow: 0 0 3px $gray-800;
}
}

View File

@ -0,0 +1,57 @@
@use '../../scss/_bootstrap-extended/include' as light;
@use '../../scss/_bootstrap-extended/include-dark' as dark;
@import 'datatables.net-responsive-bs5/css/responsive.bootstrap5';
@import 'mixins';
// Responsive table area '+' icon position
table.dataTable.dtr-column > tbody > tr > td.control,
table.dataTable.dtr-column > tbody > tr > th.control {
position: relative;
&:before,
&:before {
position: absolute;
line-height: 0.9em;
font-weight: light.$font-weight-medium;
height: 0.85em;
width: 0.85em;
color: light.$white;
border-radius: 1em;
box-sizing: content-box;
text-align: center;
font-family: 'Courier New', Courier, monospace;
content: '+';
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
table.dataTable.dtr-column > tbody > tr.parent td.dtr-control:before,
table.dataTable.dtr-column > tbody > tr.parent th.dtr-control:before,
table.dataTable.dtr-column > tbody > tr.parent td.control:before,
table.dataTable.dtr-column > tbody > tr.parent th.control:before {
content: '+';
}
// To scroll within datatable area
@media screen and (max-width: 1399.98px) {
table.dataTable.table-responsive {
display: block;
}
}
// Modal table style
.modal.dtr-bs-modal {
.modal-body {
padding: 0;
}
.table {
tr:last-child > td {
border-bottom: 0;
}
.btn {
box-shadow: none !important;
}
.emp_name {
font-weight: light.$font-weight-medium;
}
}
}

View File

@ -0,0 +1,25 @@
@use '../../scss/_bootstrap-extended/include' as light;
@use '../../scss/_bootstrap-extended/include-dark' as dark;
@import '../../scss/_custom-variables/libs';
@import 'datatables.net-rowgroup-bs5/css/rowGroup.bootstrap5';
// Light style
@if $enable-light-style {
.light-style {
tr.group,
tr.group:hover {
background-color: light.$gray-100 !important;
}
}
}
// Dark style
@if $enable-dark-style {
.dark-style {
tr.group,
tr.group:hover {
background-color: rgba(dark.$base, 0.1) !important;
}
}
}

View File

@ -0,0 +1,39 @@
@use '../../scss/_bootstrap-extended/include' as light;
@use '../../scss/_bootstrap-extended/include-dark' as dark;
@use '../../scss/_components/include' as comp;
@import '../../scss/_custom-variables/libs';
@import 'datatables.net-select-bs5/css/select.bootstrap5';
// Background color for select row
table.dataTable tbody > tr.selected td,
table.dataTable tbody > tr > .selected td {
background-color: rgba(light.$primary, 0.08);
box-shadow: none;
}
// Light style
@if $enable-light-style {
.light-style {
table.dataTable tbody tr.selected td,
table.dataTable tbody th.selected td,
table.dataTable tbody td.selected td {
color: light.$body-color !important;
}
}
}
// Dark Style
@if $enable-dark-style {
.dark-style {
table.dataTable tbody > tr.selected > *,
table.dataTable tbody > tr > .selected > * {
box-shadow: inset 0 0 0 dark.$gray-50;
color: dark.$table-active-color;
}
table.dataTable tbody tr.selected td,
table.dataTable tbody th.selected td,
table.dataTable tbody td.selected td {
color: inherit;
}
}
}

View File

@ -0,0 +1,5 @@
@mixin dropzone-theme($border) {
.dropzone.dz-drag-hover {
border-color: $border !important;
}
}

View File

@ -0,0 +1,56 @@
import Dropzone from 'dropzone/dist/dropzone';
Dropzone.autoDiscover = false;
// File upload progress animation
Dropzone.prototype.uploadFiles = function (files) {
const minSteps = 6;
const maxSteps = 60;
const timeBetweenSteps = 100;
const bytesPerStep = 100000;
const isUploadSuccess = true;
const self = this;
for (let i = 0; i < files.length; i++) {
const file = files[i];
const totalSteps = Math.round(Math.min(maxSteps, Math.max(minSteps, file.size / bytesPerStep)));
for (let step = 0; step < totalSteps; step++) {
const duration = timeBetweenSteps * (step + 1);
setTimeout(
(function (file, totalSteps, step) {
return function () {
file.upload = {
progress: (100 * (step + 1)) / totalSteps,
total: file.size,
bytesSent: ((step + 1) * file.size) / totalSteps
};
self.emit('uploadprogress', file, file.upload.progress, file.upload.bytesSent);
if (file.upload.progress === 100) {
if (isUploadSuccess) {
file.status = Dropzone.SUCCESS;
self.emit('success', file, 'success', null);
} else {
file.status = Dropzone.ERROR;
self.emit('error', file, 'Some upload error', null);
}
self.emit('complete', file);
self.processQueue();
}
};
})(file, totalSteps, step),
duration
);
}
}
};
try {
window.Dropzone = Dropzone;
} catch (e) {}
export { Dropzone };

View File

@ -0,0 +1,460 @@
// Dropzone
@use '../../scss/_bootstrap-extended/include' as light;
@use '../../scss/_bootstrap-extended/include-dark' as dark;
@import '../../scss/_custom-variables/libs';
$dz-box-padding: 1.25rem !default;
$dz-icon-size: 1.875rem !default;
$dz-thumbnail-width: 10rem !default;
$dz-thumbnail-height: 7.5rem !default;
$dz-preview-padding: 0.625rem !default;
$dz-progress-height: 0.5rem !default;
$dz-icon-block-size: 3.75rem !default;
// common styles
.dropzone {
width: 100%;
position: relative;
cursor: pointer;
border-radius: light.$border-radius-lg;
// Disabled
&:not(.dz-clickable) {
opacity: 0.5;
cursor: not-allowed;
}
// Hover
&.dz-drag-hover {
border-style: solid;
.dz-message {
opacity: 0.5;
}
}
}
.dz-message {
font-size: light.$h4-font-size;
&:before {
content: '';
border-radius: 6px;
position: absolute;
top: 5rem;
left: calc(50% - 23px);
display: inline-block;
height: 40px;
width: 40px;
background-repeat: no-repeat !important;
background-position: center !important;
}
.note {
font-size: light.$font-size-base;
}
}
// Fallback
.dz-browser-not-supported {
&.dropzone-box {
min-height: auto !important;
border: none !important;
border-radius: 0 !important;
padding: 0 !important;
width: auto !important;
cursor: default !important;
transition: none;
}
.dz-message {
display: none !important;
}
}
// Default message
.dz-started .dz-message {
display: none;
}
.dz-message {
margin: 8rem 0 3rem;
font-weight: 500;
text-align: center;
.note {
display: block;
margin-top: 0.5rem;
}
}
// styles for dropzone in ecommerce
.app-ecommerce {
.dz-message {
margin-top: 5rem;
&::before {
top: 3rem;
}
}
}
// Preview
.dz-preview {
position: relative;
vertical-align: top;
background: #fff;
font-size: 0.8125rem;
margin: 1rem;
margin-right: $dz-box-padding - 1;
box-sizing: content-box;
cursor: default;
@include light.media-breakpoint-down(sm) {
margin: $dz-box-padding - 0.5;
}
}
// File information
.dz-filename {
position: absolute;
width: 100%;
overflow: hidden;
padding: $dz-preview-padding $dz-preview-padding 0 $dz-preview-padding;
background: light.$white;
white-space: nowrap;
text-overflow: ellipsis;
&:hover {
white-space: normal;
text-overflow: inherit;
}
}
.dz-size {
padding: 1.875rem $dz-preview-padding $dz-preview-padding $dz-preview-padding;
font-size: 0.6875rem;
font-style: italic;
}
// Progressbar
.dz-preview .progress,
.dz-preview .progess-bar {
height: $dz-progress-height;
}
.dz-preview .progress {
position: absolute;
left: 1.25rem;
right: 1.25rem;
top: 50%;
margin-top: -$dz-progress-height * 0.5;
z-index: 30;
}
.dz-complete .progress {
display: none;
}
// Thumbnail
.dz-thumbnail {
position: relative;
padding: $dz-preview-padding;
height: $dz-thumbnail-height;
text-align: center;
box-sizing: content-box;
> img,
.dz-nopreview {
top: 50%;
position: relative;
transform: translateY(-50%) scale(1);
margin: 0 auto;
display: block;
}
> img {
max-height: 100%;
max-width: 100%;
}
}
.dz-nopreview {
font-weight: light.$font-weight-medium;
text-transform: uppercase;
font-size: 0.6875rem;
}
.dz-thumbnail img[src] ~ .dz-nopreview {
display: none;
}
// Remove link
.dz-remove {
display: block;
text-align: center;
padding: 0.375rem 0;
font-size: 0.75rem;
&:hover,
&:focus {
text-decoration: none;
border-top-color: transparent;
}
}
// error/success states
.dz-error-mark,
.dz-success-mark {
position: absolute;
left: 50%;
top: 50%;
display: none;
margin-left: -$dz-icon-block-size * 0.5;
margin-top: -$dz-icon-block-size * 0.5;
height: $dz-icon-block-size;
width: $dz-icon-block-size;
border-radius: 50%;
background-position: center center;
background-size: $dz-icon-size $dz-icon-size;
background-repeat: no-repeat;
box-shadow: 0 0 1.25rem rgba(0, 0, 0, 0.06);
}
.dz-success-mark {
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%235cb85c' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3E%3C/svg%3E");
}
.dz-error-mark {
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23d9534f' viewBox='-2 -2 7 7'%3E%3Cpath stroke='%23d9534f' d='M0 0l3 3m0-3L0 3'/%3E%3Ccircle r='.5'/%3E%3Ccircle cx='3' r='.5'/%3E%3Ccircle cy='3' r='.5'/%3E%3Ccircle cx='3' cy='3' r='.5'/%3E%3C/svg%3E");
}
.dz-error-message {
position: absolute;
top: -1px;
left: -1px;
bottom: -1px;
right: -1px;
display: none;
color: light.$white;
z-index: 40;
padding: 0.75rem;
text-align: left;
overflow: auto;
font-weight: light.$font-weight-medium;
@include app-rtl {
text-align: right;
}
}
// Error state
.dz-error {
.dz-error-message {
display: none;
}
.dz-error-mark {
display: block;
}
&:hover {
.dz-error-message {
display: block;
}
.dz-error-mark {
display: none;
}
}
}
// Success state
.dz-success .dz-success-mark {
display: block;
}
// RTL
@include app-rtl(false) {
.dz-hidden-input {
left: auto !important;
right: 0 !important;
}
}
// Light style
@if $enable-light-style {
.light-style {
$dz-overlay-bg: light.$dark;
$dz-thumbnail-bg: light.$gray-25;
$dz-border-color: light.$card-border-color;
.dropzone {
border: 2px dashed $dz-border-color;
}
.dz-preview {
border: light.$card-border-width solid $dz-border-color;
border-radius: light.$border-radius;
box-shadow: light.$card-box-shadow;
}
.dz-message {
color: light.$headings-color;
&:before {
background-image: light.str-replace(
light.str-replace(light.$upload-icon, 'currentColor', light.$headings-color),
'#',
'%23'
) !important;
background: #eeedf0;
}
.note {
color: light.$body-color;
font-weight: light.$font-weight-normal;
}
}
.dz-thumbnail {
border-bottom: 1px solid light.rgba-to-hex($dz-border-color);
background: $dz-thumbnail-bg;
@include light.border-top-radius(if(light.$border-radius, calc(#{light.$border-radius} - 1px), 0));
}
.dz-size {
color: light.$text-muted;
}
.dz-remove {
color: light.$body-color;
border-top: 1px solid light.rgba-to-hex($dz-border-color);
@include light.border-bottom-radius(if(light.$border-radius, calc(#{light.$border-radius} - 1px), 0));
&:hover,
&:focus {
color: light.$body-color;
background: light.$gray-100;
}
}
.dz-nopreview {
color: light.$text-muted;
}
.dz-error-mark,
.dz-success-mark {
background-color: rgba($dz-overlay-bg, 0.5);
}
.dz-error-message {
background: rgba(map-get(light.$theme-colors, danger), 0.8);
@include light.border-top-radius(light.$border-radius);
}
@include light.media-breakpoint-up(sm) {
.dz-preview {
display: inline-block;
width: $dz-thumbnail-width + ($dz-preview-padding * 2);
}
.dz-thumbnail {
width: $dz-thumbnail-width;
}
}
}
}
// dark style
@if $enable-dark-style {
.dark-style {
$dz-overlay-bg: dark.$dark;
$dz-thumbnail-bg: dark.$gray-25;
$dz-border-color: dark.$card-border-color;
.dropzone {
border: 2px dashed $dz-border-color;
}
.dz-preview {
background: dark.$card-bg;
border: dark.$card-border-width solid $dz-border-color;
border-radius: dark.$border-radius;
box-shadow: dark.$card-box-shadow;
}
.dz-message {
color: dark.$headings-color;
&:before {
background-image: light.str-replace(
light.str-replace(light.$upload-icon, 'currentColor', dark.$headings-color),
'#',
'%23'
) !important;
background: #373b50;
}
.note {
color: dark.$body-color;
font-weight: dark.$font-weight-normal;
}
}
.dz-filename {
background: dark.$card-bg;
padding-top: 0.25rem;
padding-bottom: 0.25rem;
border-bottom: dark.$card-border-width solid $dz-border-color;
}
.dz-size {
color: dark.$text-muted;
}
.dz-thumbnail {
border-bottom: 1px solid $dz-border-color;
background: $dz-thumbnail-bg;
@include dark.border-top-radius(if(dark.$border-radius, calc(#{dark.$border-radius} - 1px), 0));
}
.dz-nopreview {
color: dark.$text-muted;
}
.dz-remove {
color: dark.$body-color;
border-top: 1px solid $dz-border-color;
@include dark.border-bottom-radius(if(dark.$border-radius, calc(#{dark.$border-radius} - 1px), 0));
&:hover,
&:focus {
color: dark.$body-color;
background: dark.$gray-100;
}
}
.dz-error-mark,
.dz-success-mark {
background-color: rgba($dz-overlay-bg, 0.5);
}
.dz-error-message {
background: rgba(map-get(dark.$theme-colors, danger), 0.8);
@include dark.border-top-radius(dark.$border-radius);
}
@include dark.media-breakpoint-up(sm) {
.dz-preview {
display: inline-block;
width: $dz-thumbnail-width + ($dz-preview-padding * 2);
}
.dz-thumbnail {
width: $dz-thumbnail-width;
}
}
}
}

View File

@ -0,0 +1,114 @@
@import '../../scss/_bootstrap-extended/functions';
@mixin flatpickr-theme($background, $color: null) {
$in-range-bg: rgba-to-hex(rgba($background, 0.16), $card-bg);
$color: if($color, $color, color-contrast($background));
$in-range-color: $background;
.flatpickr-day {
&.today,
&.today:hover {
color: $background !important;
border-color: rgba-to-hex(rgba($background, 0.16), $card-bg);
background-color: rgba-to-hex(rgba($background, 0.16), $card-bg) !important;
}
&.inRange,
&.nextMonthDay.inRange,
&.prevMonthDay.inRange,
&.today.inRange,
&.prevMonthDay.today.inRange,
&.nextMonthDay.today.inRange {
color: $background !important;
background: $in-range-bg !important;
border-color: $in-range-bg !important;
}
&.selected,
&.selected.inRange,
&.selected:focus,
&.selected:hover,
&.selected.nextMonthDay,
&.selected.prevMonthDay,
&.startRange,
&.startRange.inRange,
&.startRange:focus,
&.startRange:hover,
&.startRange.nextMonthDay,
&.startRange.prevMonthDay,
&.endRange,
&.endRange.inRange,
&.endRange:focus,
&.endRange:hover,
&.endRange.nextMonthDay,
&.endRange.prevMonthDay,
&.week.selected {
color: $color !important;
background: $background !important;
border-color: $background !important;
box-shadow: 0 0.125rem 0.375rem 0 rgba($background, 0.3);
}
}
}
@mixin flatpickr-dark-theme($background, $color: null) {
$color: if($color, $color, color-contrast($background));
$in-range-bg: rgba-to-hex(rgba($background, 0.16), $card-bg);
$in-range-color: $background;
.flatpickr-calendar .numInputWrapper span {
&.arrowUp:after {
border-bottom-color: $color;
}
&.arrowDown:after {
border-top-color: $color;
}
}
.flatpickr-day {
&.today,
&.today:hover,
&.inRange {
color: $background !important;
border-color: rgba-to-hex(rgba($background, 0.16), $card-bg) !important;
background-color: rgba-to-hex(rgba($background, 0.16), $card-bg) !important;
}
&.inRange,
&.nextMonthDay.inRange,
&.prevMonthDay.inRange,
&.today.inRange,
&.nextMonthDay.today.inRange,
&.prevMonthDay.today.inRange {
border-color: $in-range-bg !important;
background: $in-range-bg !important;
color: $background !important;
}
&.selected,
&.selected.inRange,
&.selected:focus,
&.selected:hover,
&.selected.prevMonthDay,
&.selected.nextMonthDay,
&.startRange,
&.startRange.inRange,
&.startRange:focus,
&.startRange:hover,
&.startRange.prevMonthDay,
&.startRange.nextMonthDay,
&.endRange,
&.endRange.inRange,
&.endRange:focus,
&.endRange:hover,
&.endRange.nextMonthDay,
&.endRange.prevMonthDay,
&.week.selected {
background: $background !important;
border-color: $background !important;
color: $color !important;
box-shadow: 0 0.125rem 0.375rem 0 rgba($background, 0.3);
}
}
}

View File

@ -0,0 +1,7 @@
import flatpickr from 'flatpickr/dist/flatpickr';
try {
window.flatpickr = flatpickr;
} catch (e) {}
export { flatpickr };

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,23 @@
@mixin fullcalendar-theme($background, $color) {
.fc {
// FC event
@include bg-label-variant('.fc-event-primary:not(.fc-list-event)', $background);
// FC list event
.fc-event-primary.fc-list-event {
.fc-list-event-dot {
border-color: $background !important;
}
}
.fc-button-primary:not(.fc-prev-button):not(.fc-next-button) {
background-color: rgba($background, 0.16) !important;
border: 0;
color: $background;
&.fc-button-active,
&:hover {
background-color: rgba($background, 0.24) !important;
color: $background;
}
}
}
}

View File

@ -0,0 +1,22 @@
import { Calendar } from '@fullcalendar/core';
import dayGridPlugin from '@fullcalendar/daygrid';
import interactionPlugin from '@fullcalendar/interaction';
import listPlugin from '@fullcalendar/list';
import timegridPlugin from '@fullcalendar/timegrid';
const calendarPlugins = {
dayGrid: dayGridPlugin,
interaction: interactionPlugin,
list: listPlugin,
timeGrid: timegridPlugin
};
try {
window.Calendar = Calendar;
window.dayGridPlugin = dayGridPlugin;
window.interactionPlugin = interactionPlugin;
window.listPlugin = listPlugin;
window.timegridPlugin = timegridPlugin;
} catch (e) {}
export { Calendar, dayGridPlugin, interactionPlugin, listPlugin, timegridPlugin };

View File

@ -0,0 +1,535 @@
@use '../../scss/_bootstrap-extended/include' as light;
@use '../../scss/_bootstrap-extended/include-dark' as dark;
@import '../../scss/_custom-variables/libs';
@import 'mixins';
$fullcalendar-event-padding-y: 0.25rem !default;
$fullcalendar-event-padding-x: 0.75rem !default;
$fullcalendar-event-margin-top: 0.625rem !default;
$fullcalendar-event-font-size: light.$font-size-base !default;
$fullcalendar-event-font-weight: light.$font-weight-medium !default;
$fullcalendar-toolbar-btn-padding: light.$input-btn-padding-y - 0.115 light.$input-btn-padding-x !default;
$fullcalendar-fc-popover-z-index: 1090 !default;
$fullcalendar-event-border-radius: light.$border-radius-sm !default;
$fullcalendar-today-background-light: light.rgba-to-hex(light.$gray-50, light.$rgba-to-hex-bg) !default;
$fullcalendar-today-background-dark: dark.rgba-to-hex(dark.$gray-50, dark.$rgba-to-hex-bg) !default;
// Calendar
.fc {
.fc-scrollgrid-section {
height: 0px;
}
a[data-navlink]:hover {
text-decoration: none;
}
.fc-timegrid-slot {
height: 4em !important;
}
.fc-timeGridWeek-view {
.fc-timegrid-slot-minor {
border-top-style: none;
}
}
.fc-timeGridDay-view {
.fc-timegrid-slot-minor {
border-top-style: solid;
}
}
.fc-col-header-cell-cushion {
padding-top: 8.7px !important;
padding-bottom: 8.7px !important;
}
.fc-toolbar {
flex-wrap: wrap;
.fc-prev-button,
.fc-next-button {
display: inline-block;
background-color: transparent;
border-color: transparent;
&:hover,
&:active,
&:focus {
background-color: transparent !important;
border-color: transparent !important;
box-shadow: none !important;
}
}
.fc-button {
border-radius: light.$border-radius;
&:not(.fc-next-button):not(.fc-prev-button) {
padding: $fullcalendar-toolbar-btn-padding;
&:active,
&:focus {
box-shadow: none !important ;
}
}
}
> * > :not(:first-child) {
margin-left: 0 !important;
@include app-rtl(true) {
margin-right: 0 !important;
}
}
.fc-toolbar-chunk {
display: flex;
align-items: center;
}
.fc-button-group {
.fc-button {
text-transform: capitalize;
}
& + div {
display: flex;
align-items: center;
flex-wrap: wrap;
}
}
.fc--button:empty,
.fc-toolbar-chunk:empty {
display: none;
}
.fc-sidebarToggle-button + div {
margin-left: 0;
}
}
table.fc-scrollgrid {
.fc-col-header {
.fc-col-header-cell {
border-left: none;
}
}
}
.fc-view-harness {
min-height: 650px;
.fc-col-header-cell-cushion {
padding-bottom: 3px;
padding-top: 3px;
}
// To remove border on weekday row
.fc-scrollgrid-section-header > * {
@include app-ltr(true) {
border-inline-end-width: 0px;
}
@include app-rtl(true) {
border-inline-start-width: 0px;
}
}
.fc-timegrid-event .fc-event-time {
font-size: 0.6875rem;
}
.fc-v-event .fc-event-title {
font-size: $fullcalendar-event-font-size;
padding-top: 0.2rem;
font-weight: $fullcalendar-event-font-weight;
}
.fc-timegrid-event .fc-event-main {
padding: $fullcalendar-event-padding-y $fullcalendar-event-padding-x 0;
}
}
.fc-daygrid-day-events {
.fc-event,
.fc-more-link {
margin-inline: 0.5rem !important;
}
}
// To fix firefox thead border issue
.fc-day-today {
background-clip: padding-box;
}
//! Fix: white color issue of event text
.fc-h-event .fc-event-main,
.fc-v-event .fc-event-main {
color: inherit !important;
}
.fc-daygrid-block-event .fc-event-time,
.fc-daygrid-dot-event .fc-event-title {
font-weight: $fullcalendar-event-font-weight;
}
.fc-daygrid-body-natural {
.fc-daygrid-day-events {
margin-top: 0.94rem !important;
margin-bottom: 0.94rem !important;
}
}
.fc-view-harness {
margin: 0 -1.5rem;
.fc-daygrid-body {
.fc-daygrid-day {
.fc-daygrid-day-top {
flex-direction: row;
.fc-daygrid-day-number {
float: left;
padding: 0.5rem;
}
}
.fc-daygrid-day-bottom .fc-daygrid-more-link {
margin-top: 0.625rem;
}
}
}
.fc-event {
font-size: $fullcalendar-event-font-size;
font-weight: $fullcalendar-event-font-weight;
padding: $fullcalendar-event-padding-y $fullcalendar-event-padding-x;
border-radius: $fullcalendar-event-border-radius;
border: 0;
.fc-event-title {
font-weight: light.$font-weight-medium;
}
}
.fc-daygrid-event-harness {
// ! week & day events are using this style for all day only, not for other events
.fc-event {
&.private-event {
background-color: transparent !important;
border-color: transparent !important;
}
}
}
.fc-event .fc-daygrid-event-dot {
display: none;
}
}
.fc-daygrid-event-harness + .fc-daygrid-event-harness .fc-daygrid-event {
margin-top: $fullcalendar-event-margin-top !important;
}
.fc-timegrid {
.fc-timegrid-divider {
display: none;
}
.fc-timegrid-event {
border-radius: 0px;
box-shadow: none;
padding-top: $fullcalendar-event-padding-x;
.fc-event-time {
font-size: inherit;
}
}
}
.fc-daygrid-event-harness-abs .fc-event {
margin-bottom: 0.625rem;
}
.fc-timegrid-slot-label-frame {
text-align: center;
}
.fc-timegrid-axis-cushion,
.fc-timegrid-slot-label-cushion {
font-size: light.$font-size-sm;
}
.fc-timegrid-axis-cushion {
text-transform: capitalize;
padding: 0.5rem 0.4375rem;
}
.fc-timegrid-slot-label-cushion {
text-transform: uppercase;
padding: $fullcalendar-event-padding-x !important;
}
.fc-list-day-cushion,
.fc-list-table td {
padding-inline: 1rem;
}
.fc-popover {
z-index: $fullcalendar-fc-popover-z-index !important;
.fc-popover-header {
padding: 0.566rem;
}
}
.fc-list {
.fc-list-table {
border-bottom: 1px solid;
}
}
&.fc-theme-standard {
.fc-list {
border: none;
}
}
.fc-day-other {
.fc-daygrid-day-top {
opacity: 1;
}
}
}
// Light style
@if $enable-light-style {
.light-style {
.fc {
.fc-toolbar {
.fc-prev-button,
.fc-next-button {
.fc-icon {
color: light.$headings-color;
}
}
}
.fc-col-header-cell-cushion {
color: light.$headings-color;
}
&.fc-theme-standard .fc-list-day-cushion {
background-color: $fullcalendar-today-background-light !important;
}
table.fc-scrollgrid {
border-color: light.$border-color;
.fc-col-header {
tbody {
border: none;
}
.fc-col-header-cell {
border-color: light.$border-color;
}
}
td {
border-color: light.$border-color;
}
}
.fc-timegrid-axis-cushion {
color: light.$text-muted;
}
.fc-timegrid-slot-label-cushion {
color: light.$headings-color;
}
.private-event {
.fc-event-time,
.fc-event-title {
color: light.$danger;
}
}
.fc-day-today:not(.fc-col-header-cell) {
background-color: $fullcalendar-today-background-light !important;
.fc-popover-body {
background-color: light.$card-bg !important;
}
}
.fc-popover {
.fc-popover-header {
background: light.$body-bg;
}
}
.fc-list {
.fc-list-table {
th {
border: 0;
background: light.$body-bg;
}
.fc-list-event {
cursor: pointer;
&:hover {
td {
background-color: light.$gray-25;
}
}
td {
border-color: light.$border-color;
color: light.$body-color;
}
}
.fc-list-day {
th {
color: light.$headings-color;
}
}
tbody > tr:first-child th {
border-top: 1px solid light.$border-color;
}
}
.fc-list-empty {
background-color: light.$body-bg;
}
}
// Border color
table,
tbody,
thead,
tbody td {
border-color: light.$border-color;
}
.fc-day-other {
.fc-daygrid-day-top {
color: light.$text-muted;
}
}
}
// ? Style event here
@each $color, $value in light.$theme-colors {
// FC event
@include light.bg-label-variant('.fc-event-#{$color}:not(.fc-list-event)', $value);
// FC list event
.fc-event-#{$color}.fc-list-event {
.fc-list-event-dot {
border-color: $value !important;
}
}
}
}
}
// Dark Style
@if $enable-dark-style {
.dark-style {
.fc {
.fc-toolbar {
.fc-prev-button,
.fc-next-button {
.fc-icon {
color: dark.$headings-color;
}
}
.fc-sidebarToggle-button {
color: dark.$white;
}
}
.fc-col-header-cell-cushion {
color: dark.$headings-color;
}
&.fc-theme-standard .fc-list-day-cushion {
background-color: $fullcalendar-today-background-dark !important;
}
.fc-timegrid-axis-cushion {
color: dark.$text-muted;
}
.fc-timegrid-slot-label-cushion {
color: dark.$headings-color;
}
table.fc-scrollgrid {
border-color: dark.$border-color;
.fc-col-header {
tbody {
border: none;
}
.fc-col-header-cell {
border-color: dark.$border-color;
}
}
td {
border-color: dark.$border-color;
}
}
.private-event {
.fc-event-time,
.fc-event-title {
color: dark.$danger;
}
}
.fc-day-today:not(.fc-col-header-cell) {
background-color: $fullcalendar-today-background-dark !important;
.fc-popover-body {
background-color: dark.$card-bg !important;
}
}
.fc-divider {
background: dark.$border-color;
border-color: dark.$border-color;
}
.fc-popover {
background-color: dark.$body-bg;
border: 0;
.fc-popover-header {
background-color: dark.$light;
}
}
.fc-list {
.fc-list-table {
th {
border: 0;
background: dark.$body-bg;
}
.fc-list-event {
cursor: pointer;
&:hover {
td {
background-color: dark.$gray-50;
}
}
td {
border-color: dark.$border-color;
color: dark.$body-color;
}
}
.fc-list-day {
th {
color: dark.$headings-color;
}
}
tbody > tr:first-child th {
border-top: 1px solid dark.$border-color;
}
}
.fc-list-empty {
background-color: dark.$body-bg;
}
}
table,
.fc-timegrid-axis,
tbody,
thead,
tbody td {
border-color: dark.$border-color;
}
// FC day
.fc-timegrid-axis-cushion.fc-scrollgrid-shrink-cushion {
color: dark.$text-muted;
}
// FC table list disabled bg
.fc-day-disabled {
background-color: rgba(dark.$base, 0.16);
}
.fc-day-other {
.fc-daygrid-day-top {
color: dark.$text-muted;
}
}
}
// ? Style event here
@each $color, $value in dark.$theme-colors {
// FC event
@include dark.bg-label-variant('.fc-event-#{$color}:not(.fc-list-event)', $value);
.fc-event-#{$color}:not(.fc-list-event) {
box-shadow: none;
}
// FC list event
.fc-event-#{$color}.fc-list-event {
.fc-list-event-dot {
border-color: $value !important;
}
}
}
}
}
// Media Queries
@include light.media-breakpoint-down(sm) {
.fc {
.fc-header-toolbar {
.fc-toolbar-chunk + .fc-toolbar-chunk {
margin-top: 1rem;
}
}
}
}

View File

@ -0,0 +1 @@
import 'hammerjs/hammer.js';

View File

@ -0,0 +1,11 @@
@import '../../scss/_bootstrap-extended/_functions';
@mixin timepicker-theme($background, $color: null) {
$color: if($color, $color, color-contrast($background));
li.ui-timepicker-selected,
.ui-timepicker-list .ui-timepicker-selected:hover {
color: $color !important;
background: $background !important;
}
}

View File

@ -0,0 +1 @@
import 'timepicker/jquery.timepicker';

View File

@ -0,0 +1,116 @@
@use '../../scss/_bootstrap-extended/include' as light;
@use '../../scss/_bootstrap-extended/include-dark' as dark;
@import '../../scss/_custom-variables/libs';
.ui-timepicker-wrapper {
max-height: 10rem;
overflow-y: auto;
margin: 0.125rem 0;
background: light.$white;
background-clip: padding-box;
outline: none;
}
.ui-timepicker-list {
list-style: none;
padding: 0.125rem 0;
margin: 0;
}
.ui-timepicker-duration {
margin-left: 0.25rem;
@include app-rtl {
margin-left: 0;
margin-right: 0.25rem;
}
}
.ui-timepicker-list li {
padding: 0.25rem 0.75rem;
margin: 0.125rem 0.875rem;
white-space: nowrap;
cursor: pointer;
list-style: none;
border-radius: light.$dropdown-border-radius;
&.ui-timepicker-disabled,
&.ui-timepicker-selected.ui-timepicker-disabled {
background: light.$white !important;
cursor: default !important;
}
}
@if $enable-light-style {
.light-style {
.ui-timepicker-wrapper {
padding: light.$dropdown-padding-y;
z-index: light.$zindex-popover;
background: light.$dropdown-bg;
box-shadow: light.$card-box-shadow;
border: light.$dropdown-border-width solid light.$dropdown-border-color;
@include light.border-radius(light.$border-radius);
}
.ui-timepicker-list li {
color: light.$dropdown-link-color;
&:hover {
background: light.$dropdown-link-hover-bg;
}
&:not(.ui-timepicker-selected) {
.ui-timepicker-duration {
color: light.$text-muted;
.ui-timepicker-list:hover & {
color: light.$text-muted;
}
}
}
}
.ui-timepicker-list li.ui-timepicker-disabled,
.ui-timepicker-list li.ui-timepicker-selected.ui-timepicker-disabled {
background: light.$dropdown-bg !important;
color: light.$dropdown-link-disabled-color !important;
}
}
}
@if $enable-dark-style {
.dark-style {
.ui-timepicker-wrapper {
border: dark.$dropdown-border-width solid dark.$dropdown-border-color;
padding: dark.$dropdown-padding-y 0;
z-index: dark.$zindex-popover;
background: dark.$dropdown-bg;
box-shadow: dark.$card-box-shadow;
@include dark.border-radius(dark.$border-radius);
}
.ui-timepicker-list li {
color: dark.$dropdown-link-color;
&:hover {
background: dark.$dropdown-link-hover-bg;
}
&:not(.ui-timepicker-selected) {
.ui-timepicker-duration {
color: dark.$text-muted;
.ui-timepicker-list:hover & {
color: dark.$text-muted;
}
}
}
}
.ui-timepicker-list li.ui-timepicker-disabled,
.ui-timepicker-list li.ui-timepicker-selected.ui-timepicker-disabled {
color: dark.$dropdown-link-disabled-color !important;
background: dark.$dropdown-bg !important;
}
}
}

View File

@ -0,0 +1,8 @@
import jQuery from 'jquery/dist/jquery';
const $ = jQuery;
try {
window.jQuery = window.$ = jQuery;
} catch (e) {}
export { jQuery, $ };

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 696 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 618 B

View File

@ -0,0 +1,19 @@
import leaFlet from 'leaflet';
import markerIcon2x from 'leaflet/dist/images/marker-icon-2x.png';
import markerIcon from 'leaflet/dist/images/marker-icon.png';
import markerShadow from 'leaflet/dist/images/marker-shadow.png';
delete leaFlet.Icon.Default.prototype._getIconUrl;
leaFlet.Icon.Default.mergeOptions({
iconRetinaUrl: markerIcon2x,
iconUrl: markerIcon,
shadowUrl: markerShadow
});
try {
window.leaFlet = leaFlet;
} catch (e) {}
export { leaFlet };

View File

@ -0,0 +1,46 @@
@import '../../scss/_bootstrap-extended/include';
@import '../../scss/_custom-variables/libs';
@import 'leaflet/dist/leaflet';
.leaflet-map {
height: 400px;
}
.leaflet-pane {
z-index: 1;
}
// RTL
@include app-rtl(false) {
.leaflet-map {
.leaflet-control-container {
.leaflet-left {
right: 0;
left: unset;
.leaflet-control-zoom,
.leaflet-control-layers {
margin-left: 0;
margin-right: 10px;
}
}
.leaflet-right {
left: 0;
right: unset;
.leaflet-control-zoom,
.leaflet-control-layers {
margin-left: 10px;
margin-right: 0px;
}
}
}
}
}
//Map tooltip border radius
.leaflet-popup {
.leaflet-popup-content-wrapper {
border-radius: $border-radius;
}
}

View File

@ -0,0 +1,7 @@
import moment from 'moment/moment';
try {
window.moment = moment;
} catch (e) {}
export { moment };

View File

@ -0,0 +1,3 @@
import nodeWaves from 'node-waves/src/js/waves';
window.Waves = nodeWaves;

View File

@ -0,0 +1,4 @@
// Waves
// *******************************************************************************
@import 'node-waves/src/scss/waves';

View File

@ -0,0 +1,26 @@
@mixin nouislider-variant($parent, $background) {
#{$parent}.noUi-target {
// If slider is not disabled
&:not([disabled]) {
background: rgba($background, 0.16);
.noUi-connect {
background: $background;
}
.noUi-handle {
border-color: $background;
&:hover {
box-shadow: 0 0 0 8px rgba($background, 0.16);
}
&:active,
&:focus {
box-shadow: 0 0 0 13px rgba($background, 0.16);
}
}
}
}
}
@mixin nouislider-theme($background) {
@include nouislider-variant('', $background);
}

View File

@ -0,0 +1,7 @@
import noUiSlider from 'nouislider';
try {
window.noUiSlider = noUiSlider;
} catch (e) {}
export { noUiSlider };

View File

@ -0,0 +1,398 @@
@use '../../scss/_bootstrap-extended/include' as light;
@use '../../scss/_bootstrap-extended/include-dark' as dark;
@import 'nouislider/dist/nouislider';
@import '../../scss/_custom-variables/libs';
@import 'mixins';
$noUiSlider-handle-color: #fff !default;
$noUiSlider-handle-width: 1.375rem !default;
$noUiSlider-handle-height: 1.375rem !default;
$noUiSlider-bar-height: 0.375rem !default;
$noUiSlider-vertical-height: 13.125rem !default;
$noUiSlider-tick-size: 0.5rem !default;
$noUiSlider-tick-label-font-size: light.$font-size-sm !default;
.noUi-target {
direction: ltr !important;
position: relative;
border-width: 0;
box-shadow: none;
}
.noUi-target,
.noUi-target * {
touch-action: none;
user-select: none;
box-sizing: border-box;
}
.noUi-connects {
height: $noUiSlider-bar-height;
border-radius: light.$border-radius-pill;
}
.noUi-base,
.noUi-connects {
z-index: 1;
position: relative;
height: 100%;
width: 100%;
}
.noUi-horizontal .noUi-origin {
height: 0;
@include app-ltr {
left: auto;
right: 0;
}
}
.noUi-vertical .noUi-origin {
width: 0;
}
.noUi-handle {
backface-visibility: hidden;
outline: none !important;
position: absolute;
box-shadow: none;
border: none;
transition: all 0.2s;
border: 4px solid;
background: #fff;
&:before,
&:after {
display: none;
}
}
.noUi-touch-area {
height: 100%;
width: 100%;
}
.noUi-state-tap .noUi-connect,
.noUi-state-tap .noUi-origin {
transition:
top 0.3s,
right 0.3s,
bottom 0.3s,
left 0.3s;
}
.noUi-state-drag * {
cursor: inherit !important;
}
// Slider size and handle placement
.noUi-horizontal {
height: $noUiSlider-bar-height;
margin-bottom: 3rem;
margin-top: 1.5rem;
}
.noUi-horizontal .noUi-handle {
left: -($noUiSlider-handle-width * 0.5);
width: $noUiSlider-handle-width;
height: $noUiSlider-handle-height;
top: ($noUiSlider-bar-height - $noUiSlider-handle-height) * 0.5;
@include app-ltr {
right: -($noUiSlider-handle-width * 0.5);
left: auto;
}
}
.noUi-vertical {
width: $noUiSlider-bar-height;
}
.noUi-vertical .noUi-handle {
bottom: -($noUiSlider-handle-height);
width: $noUiSlider-handle-height;
height: $noUiSlider-handle-width;
right: ($noUiSlider-bar-height - $noUiSlider-handle-height) * 0.5;
}
// Styling
.noUi-target {
border-radius: 10rem;
}
// Handles and cursors
.noUi-draggable {
cursor: ew-resize;
}
.noUi-vertical .noUi-draggable {
cursor: ns-resize;
}
.noUi-handle {
border-radius: 10rem;
background: $noUiSlider-handle-color;
cursor: pointer;
}
// Disabled state
.noUi-target[disabled] {
opacity: 0.45;
}
[disabled] .noUi-handle {
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.05);
}
[disabled].noUi-target,
[disabled].noUi-handle,
[disabled] .noUi-handle {
cursor: not-allowed;
}
// Base
.noUi-pips,
.noUi-pips * {
box-sizing: border-box;
}
.noUi-pips {
color: #999;
position: absolute;
}
// Values
.noUi-value {
position: absolute;
white-space: nowrap;
text-align: center;
font-size: $noUiSlider-tick-label-font-size;
}
// Markings
.noUi-marker {
position: absolute;
}
// Horizontal layout
.noUi-pips-horizontal {
left: 0;
top: 100%;
padding: (($noUiSlider-handle-height - $noUiSlider-bar-height) * 0.5 + 0.375rem) 0 0 0;
height: 5rem;
width: 100%;
}
.noUi-value-horizontal {
padding-top: 0.125rem;
transform: translate(-50%, 50%);
@include app-rtl {
transform: translate(50%, 50%);
}
}
.noUi-marker-horizontal.noUi-marker {
height: $noUiSlider-tick-size;
width: 1px;
}
@include app-rtl(false) {
.noUi-horizontal {
.noUi-origin {
left: 0;
}
}
}
// Vertical layout
.noUi-pips-vertical {
top: 0;
left: 100%;
padding: 0 0 0 (($noUiSlider-handle-height - $noUiSlider-bar-height) * 0.5 + 0.375rem);
height: 100%;
@include app-rtl {
right: 100%;
left: auto;
}
}
.noUi-value-vertical {
padding-left: $noUiSlider-tick-size + 0.375rem;
transform: translate(0, 50%);
@include app-rtl {
right: 100%;
padding-right: $noUiSlider-tick-size + 0.375rem;
padding-left: 0;
}
}
@include app-rtl(false) {
.noUi-marker-vertical {
right: 100%;
}
}
.noUi-marker-vertical.noUi-marker {
width: $noUiSlider-tick-size;
height: 1px;
}
// Tooltips
.noUi-tooltip {
position: absolute;
display: block;
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
text-align: center;
line-height: 1;
transition: transform 0.2s;
&::after {
content: '';
position: absolute;
width: 0;
height: 0;
clear: both;
}
}
.noUi-horizontal .noUi-tooltip {
bottom: 125%;
left: 50%;
transform: translate(-50%, -45%);
&::after {
content: '';
left: 50%;
transform: translateX(-50%);
top: 1.25rem;
border-left: 8px solid transparent;
border-right: 8px solid transparent;
}
}
.noUi-vertical .noUi-tooltip {
top: 50%;
right: 125%;
transform: translate(-15%, -52%);
&::after {
content: '';
top: 14%;
right: -5px;
border-top: 8px solid transparent;
border-bottom: 8px solid transparent;
@include app-rtl {
left: -14px;
right: auto;
}
}
@include app-rtl {
right: auto;
left: 125%;
transform: translate(15%, -52%);
}
}
// Light style
@if $enable-light-style {
.light-style {
$noUiSlider-default-bg: light.$gray-400;
$noUiSlider-tick-label-color: light.$text-light;
.noUi-target {
.noUi-handle {
box-shadow: light.$form-range-thumb-box-shadow;
}
}
.noUi-value {
color: $noUiSlider-tick-label-color;
}
.noUi-marker {
background: $noUiSlider-tick-label-color;
}
.noUi-tooltip {
font-size: light.$small-font-size;
color: light.$tooltip-color;
border: none;
background: light.$tooltip-bg;
}
.noUi-horizontal .noUi-tooltip {
&::after {
border-top: 8px solid light.$tooltip-bg;
}
}
.noUi-vertical .noUi-tooltip {
&::after {
border-left: 8px solid light.$tooltip-bg;
}
}
@include app-rtl-style {
.noUi-vertical .noUi-tooltip {
&::after {
border-right: 8px solid light.$tooltip-bg;
border-left: 8px solid transparent;
}
}
}
@each $color, $value in light.$theme-colors {
@if $color !=primary {
@include nouislider-variant('.noUi-#{$color}', $value);
}
}
}
}
@if $enable-dark-style {
.dark-style {
$noUiSlider-default-bg: dark.$gray-400;
$noUiSlider-tick-label-color: dark.$text-light;
.noUi-target {
.noUi-handle {
box-shadow: dark.$form-range-thumb-box-shadow;
}
}
.noUi-value {
color: $noUiSlider-tick-label-color;
}
.noUi-marker {
background: $noUiSlider-tick-label-color;
}
.noUi-tooltip {
font-size: dark.$small-font-size;
color: dark.$tooltip-color;
border: none;
background: dark.$tooltip-bg;
}
.noUi-horizontal .noUi-tooltip {
&::after {
border-top: 8px solid dark.$tooltip-bg;
}
}
.noUi-vertical .noUi-tooltip {
&::after {
border-left: 8px solid dark.$tooltip-bg;
}
}
@include app-rtl-style {
.noUi-vertical .noUi-tooltip {
&::after {
border-right: 8px solid dark.$tooltip-bg;
border-left: 8px solid transparent;
}
}
}
@each $color, $value in dark.$theme-colors {
@if $color !=primary {
@include nouislider-variant('.noUi-#{$color}', $value);
}
}
}
}

View File

@ -0,0 +1,7 @@
import PerfectScrollbar from 'perfect-scrollbar/dist/perfect-scrollbar';
try {
window.PerfectScrollbar = PerfectScrollbar;
} catch (e) {}
export { PerfectScrollbar };

Some files were not shown because too many files have changed in this diff Show More