UNPKG

@xuda.io/xuda-framework-plugin-tailwind

Version:

Xuda Tailwind UI Framework plugin

612 lines (539 loc) 19.7 kB
const _colors = { primary: ' border-gray-300 bg-white bg-red-600 text-gray-700 hover:bg-gray-50 focus:ring-indigo-500 ', secondary: ' border-gray-300 bg-white bg-red-600 text-gray-700 hover:bg-gray-50 focus:ring-indigo-500 ', tertiary: ' border-gray-300 bg-white bg-red-600 text-gray-700 hover:bg-gray-50 focus:ring-indigo-500 ', success: ' border-gray-300 bg-white bg-red-600 text-gray-700 hover:bg-gray-50 focus:ring-indigo-500 ', warning: ' border-gray-300 bg-white bg-red-600 text-gray-700 hover:bg-gray-50 focus:ring-indigo-500 ', danger: ' border-gray-300 bg-white bg-red-600 text-gray-700 hover:bg-gray-50 focus:ring-indigo-500 ', light: ' border-gray-300 bg-white bg-red-600 text-gray-700 hover:bg-gray-50 focus:ring-indigo-500 ', medium: ' border-gray-300 bg-white bg-red-600 text-gray-700 hover:bg-gray-50 focus:ring-indigo-500 ', dark: ' border-gray-300 bg-white bg-red-600 text-gray-700 hover:bg-gray-50 focus:ring-indigo-500 ', }; const _fields = { init: { type: 'string', label: 'Theme Configuration', value: ` tailwind.config = { theme: { screens: { sm: '480px', md: '768px', lg: '976px', xl: '1440px', }, colors: { 'blue': '#1fb6ff', 'purple': '#7e5bef', 'pink': '#ff49db', 'orange': '#ff7849', 'green': '#13ce66', 'yellow': '#ffc82c', 'gray-dark': '#273444', 'gray': '#8492a6', 'gray-light': '#d3dce6', }, fontFamily: { sans: ['Graphik', 'sans-serif'], serif: ['Merriweather', 'serif'], }, extend: { spacing: { '128': '32rem', '144': '36rem', }, borderRadius: { '4xl': '2rem', } } } } `, helper: '<a target="_blank" href="https://ionicframework.com/docs/theming/color-generator"> Color Generator </a>', render: 'code', render_params: { lang: 'js', }, handler: function () {}, }, }; export function tabs(doc) { return { theme: { svg_icon: '<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-palette" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"> <path stroke="none" d="M0 0h24v24H0z" fill="none"/> <path d="M12 21a9 9 0 1 1 0 -18a9 8 0 0 1 9 8a4.5 4 0 0 1 -4.5 4h-2.5a2 2 0 0 0 -1 3.75a1.3 1.3 0 0 1 -1 2.25" /> <circle cx="7.5" cy="10.5" r=".5" fill="currentColor" /> <circle cx="12" cy="7.5" r=".5" fill="currentColor" /> <circle cx="16.5" cy="10.5" r=".5" fill="currentColor" /> </svg>', label: 'Theme', type: 'single', fields: { init: _fields.init, }, }, }; } export const core = class { init(setup) { if (!setup?.theme?.init) { return console.warn('UI framework theme setup not found'); } var id = 'xuda-framework-plugin-tailwind-script-' + Date.now(); const script = document.createElement('script'); script.setAttribute('id', id); script.innerHTML = setup.theme.init; document.head.append(script); return id; } discard(id) { const element = document.getElementById(id); element.remove(); } refresh(container, _ds) { return $(container); } rootTagName() { return 'div'; } customUiClasses() { return []; } renderEngineProperties() { return { restrict_tags: true, engine: function () {}, tags: { col: { attributes: { type: { label: 'Modal Position', type: 'string', render: 'select', options: [ { label: 'Stretch', value: 'stretch' }, { label: 'Start', value: 'start' }, { label: 'Center', value: 'center' }, { label: 'End', value: 'end' }, ], }, }, render() { return `<div > <button/> </div>`; }, }, }, tags2: { img: ['src', 'alt'] }, classes: [], common_tags: [], }; } }; export const bind = class { setter(elm, value) { if ($(elm).prop('tagName') === 'SELECT') { setTimeout(() => { $(elm).val(_.toString(value)); }, 250); } else { switch ($(elm).attr('type')) { case 'radio': if ($(elm).attr('value') === value) { // $(elm).attr('checked', true); $(elm).prop('checked', true); } else { // $(elm).removeAttr('checked'); $(elm).prop('checked', false); } break; case 'checkbox': if (value) { // $(elm).attr('checked', true); $(elm).prop('checked', true); } else { // $(elm).removeAttr('checked'); $(elm).prop('checked', false); } break; case 'time': if (value.length === 5) { // force adding the :00 seconds value = value + ':00'; $(elm).val(value); } break; default: // if ($(elm).prop("tagName") === "SELECT") { // setTimeout(() => { // $(elm).val(_.toString(value)); // }, 250); // } else { $(elm).val(value); // } } // $(elm).val(value); } } getter(elm) { switch ($(elm).attr('type')) { case 'radio': if ($(elm).attr('checked') || $(elm).is(':checked')) { $(elm).attr('checked', true); return $(elm).attr('value'); } break; case 'checkbox': if ($(elm).attr('checked') || $(elm).is(':checked')) { $(elm).attr('checked', true); return $(elm).attr('value'); } break; default: return $(elm).val(); } } listener(elm, callback) { $(elm).on('change', (e) => { callback(e); }); } }; export const toast = class { async create(type, message, title) { let svg = ''; switch (type) { case 'error': svg = `<svg class="w-6 h-6 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>`; console.info(message); break; case 'success': svg = `<svg class="w-6 h-6 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>`; break; case 'info': svg = `<svg class="w-6 h-6 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>`; break; case 'warning': svg = `<svg class="w-6 h-6 text-yellow-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path></svg>`; console.info(message); break; default: } this.$html = $(` <div class="w-full flex flex-col items-center space-y-4 sm:items-end"> <div class="max-w-sm w-full bg-white shadow-lg rounded-lg pointer-events-auto ring-1 ring-black ring-opacity-5 overflow-hidden"> <div class="p-4"> <div class="flex items-start"> <div class="flex-shrink-0"> ${svg} </div> <div class="ms-3 w-0 flex-1 pt-0.5"> <p class="text-sm font-medium text-gray-900"></p> ${title} <p class="text-sm text-gray-500"> ${message} </p> </div> <div class="ml-4 flex-shrink-0 flex"> <button class="bg-white rounded-md inline-flex text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"> <span class="sr-only">Close</span> <svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"> <path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path> </svg> </button> </div> </div> </div> </div> </div> `); $('#tailwind_toast_controller').append(this.$html.hide().fadeIn()); this.$html.find('button').click(() => { this.$html.remove(); }); setTimeout(() => { this.$html.fadeOut('slow', function () { $(this).remove(); }); }, 5000); } init(text) {} close() { this.$html.remove(); } }; export const loader = class { async create() { const loadingController = function () { var id = undefined; return { create: function () { id = Date.now(); }, present: function () { const $html = $(`<div id="tailwind_loader_${id}" class="absolute z-[999] inset-0 px-4 sm:inset-0 sm:flex sm:items-center sm:justify-center spinny"> <div class="absolute inset-0 transition-opacity"> <div class="absolute inset-0 rounded-md bg-gray-900 opacity-30"></div> </div> <div class="transform transition-all sm:max-w-2xl w-full h-full flex items-center" role="dialog" aria-modal="true" aria-labelledby="modal-headline"> <div class="spinner spinner-add ease-linear my-auto mx-auto"> ${text ? text : 'Please wait..'} </div> </div> </div>`); $('#tailwind_loader_' + id).remove(); $('body').prepend($html); return $html; }, dismiss: function () { $('#tailwind_loader_' + id).remove(); }, }; }; const loader = loadingController.create(); loader.present(); return loader; } init(text) {} close(id) { $('#tailwind_loader_' + id).remove(); } }; export const popover = class { async open(e) { this.SESSION_ID = e.SESSION_ID; const popoverController = function () { var id = undefined; return { create: function (opt) { id = Date.now(); }, present: function () { $('#xu_popover_modal_' + e.SESSION_ID).remove(); const $html = ` <div id="xu_popover_modal_${e.SESSION_ID}" class="absolute z-10 inline-block w-64 text-sm font-light text-gray-500 transition-opacity duration-300 bg-white border border-gray-200 rounded-lg shadow-sm dark:text-gray-400 dark:bg-gray-800 dark:border-gray-600 " > <xu-popover-content-${e.SESSION_ID}> </div> `; $('body').prepend($html); return $html; }, dismiss: function () { $('#xu_popover_modal_' + e.SESSION_ID).remove(); }, }; }; let popover = new popoverController(); popover.present(); } async set(e) {} async close(e) { $('#xu_popover_modal_' + this.SESSION_ID).remove(); } }; export const popup = class { async create(header, subheader, message, buttons) { // buttons = [ // { // label: "Dismiss", // role: "cancel", // cssClass: "secondary", // handler: () => { // callback(); // }, // }, // ]; var html_buttons = ''; buttons.forEach((val) => { html_buttons += ` <button id="${val.role || val}_button" type="button" class=" ${ _colors[val.cssClass] || _colors.secondary } mt-3 w-full inline-flex justify-center rounded-md border shadow-sm px-4 py-2 text-base font-medium focus:outline-none focus:ring-2 focus:ring-offset-2 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"> ${val.text || val} </button> `; }); this.$html = $(` <div class="fixed z-10 inset-0 overflow-y-auto" aria-labelledby="modal-title" role="dialog" aria-modal="true"> <div class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"> <div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" aria-hidden="true"></div> <span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span> <div class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"> <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> <div class="sm:flex sm:items-start"> <div class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10"> <!-- Heroicon name: outline/exclamation --> <svg class="h-6 w-6 text-red-600" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" /> </svg> </div> <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> <h3 class="text-lg leading-6 font-medium text-gray-900" id="modal-title"> ${subheader} </h3> <div class="mt-2"> <p class="text-sm text-gray-500"> ${message} </p> </div> </div> </div> </div> <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> ${html_buttons} </div> </div> </div> </div> `); $('body').append(this.$html); buttons.forEach((val) => { $(`#${val.role || val}_button`).click(() => { this.$html.remove(); if (val.handler) { val.handler(); } }); }); } async update(text) {} async close(loader) { this.$html.remove(); } }; export const modal = class { async create(e) { let template_close_btn = ` <button type="button" class=""> <svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path></svg> </button> `; let template_header = ` <div class="border-b py-3 px-4 flex items-center justify-between"> <h3 class="font-medium leading-6 text-gray-900 sm:text-lg" id="modal-title"> ${e.properties?.name} </h3> ${!e.properties?.disableModalClose ? template_close_btn : ''} </div>`; this.template = $(` <div class="relative z-10"> <div class="fixed inset-0 z-10 overflow-y-auto"> ${e.properties?.allowBackdropDismiss ? '<div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity backDrop"></div>' : ''} <div class="flex min-h-full items-${e?.properties?.modalPosition ? e.properties?.modalPosition : 'end'} justify-center sm:items-center"> <div class="relative mx-4 my-2 w-full transform overflow-hidden rounded-lg border border-gray-50 shadow-xl transition-all sm:max-w-lg bg-white"> ${!e.properties?.hideHeader ? template_header : ''} <div class="template_body"> </div> </div> </div> </div> </div> `); this.close_callback = e.close_callback; this.modal_id = e.modal_id; this.modal = $('<' + e.modal_id + '>'); $('body').append(this.modal); $(e.modal_id).html(this.template); if (!e.properties?.disableModalClose) { $(e.modal_id) .find('button') .click(() => { this.close(); }); } if (e?.properties?.allowBackdropDismiss) { $(e.modal_id) .find('.backDrop') .click(() => { this.close(); }); } return this; } async init(e) { const xu_modal_controller = document.querySelector('xu-modal-controller'); var $modal = $(e.modal_id); var params = $(xu_modal_controller).data().xuControllerParams[e.modal_id]; if (e.$container) { $modal.attr('id', e.$container.attr('id')); $.each(e.$container.data(), function (key, val) { $modal.data(key, val); }); } $modal.find('.template_body').html(params.$dialogDiv); } async present(modal) { await modal.present(); } async properties() { return { modalPosition: { label: 'Modal Position', type: 'string', render: 'select', options: [ { label: 'Stretch', value: 'stretch' }, { label: 'Start', value: 'start' }, { label: 'Center', value: 'center' }, { label: 'End', value: 'end' }, ], }, allowBackdropDismiss: { label: 'Allow Backdrop Dismiss', type: 'bool', render: 'checkbox', }, allowModalClose: { label: 'Allow Modal Close', type: 'bool', render: 'checkbox', }, hideHeader: { label: 'Hide Header', render: 'checkbox', type: 'bool', }, }; } async close() { this.modal.remove(); if (this.close_callback) this.close_callback(this.modal_id); } }; export const page = class { async create(e) { this.$page = $('<div>'); const $header = $(` <div class="flex py-3 px-2 border-b"> <h3 class="font-medium leading-6 text-gray-900 sm:text-lg" id="modal-title">${e.properties.name}</h3> </div> `); if (!e?.properties?.disablePageBack) { const $button = $(` <button type="button" class="mr-3"> <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M9.707 16.707a1 1 0 01-1.414 0l-6-6a1 1 0 010-1.414l6-6a1 1 0 011.414 1.414L5.414 9H17a1 1 0 110 2H5.414l4.293 4.293a1 1 0 010 1.414z" clip-rule="evenodd"></path></svg> </button>`) .prependTo($header) .off('click') .on('click', async () => { this.page_back_callback(); }); } if (!e?.properties?.hideHeader) { if (!e?.properties?.disablePageBack) { $header.appendTo(this.$page); } } } async init(e) { e.callback = (elm, page_back_callback) => { $(elm).append(this.$page.children()); $(elm).append(e.div); this.page_back_callback = page_back_callback; }; } async properties() { return { allowPageBack: { label: 'Allow Page Back', render: 'checkbox', type: 'bool', }, hideHeader: { label: 'Hide Header', render: 'checkbox', type: 'bool', }, }; } };