diff --git a/demo.html b/demo.html index 577b35c..590878b 100644 --- a/demo.html +++ b/demo.html @@ -22,6 +22,12 @@ About Contacts + +
+ + User Avatar +
+ diff --git a/src/css/bundle.css b/src/css/bundle.css index 85541e1..afe10ab 100644 --- a/src/css/bundle.css +++ b/src/css/bundle.css @@ -3,7 +3,7 @@ Project: kromacss Version: 1.0.2 Description: A modern, lightweight, and dependency-free CSS framework designed for simplicity, speed, and adaptability. Author: Altxria Inc. -License: MIT +License: CC BY-ND 4.0 */ /* --- design-tokens.css --- */ @@ -373,6 +373,23 @@ svg { .inline { display: inline; } +/*REMOVE HIGHLIGHT BACKGROUND*/ +.no-selection::selection { + background: transparent; + color: inherit; +} + +.no-selection::-moz-selection { + background: transparent; + color: inherit; +} + +.no-selection { + user-select: none; +} + + + /* --- flexbox.css --- */ .flex { display: flex; gap: var(--space-4); } .flex-wrap { flex-wrap: wrap; } @@ -2734,136 +2751,6 @@ blockquote { } -/* --- footer.css --- */ -/* Base Footer Styles */ -.kroma-footer { - display: flex; - flex-wrap: wrap; - justify-content: space-between; - align-items: center; - padding: var(--space-6) var(--space-8); - background-color: var(--variant-bg, var(--neutral-900)); - color: var(--variant-text, var(--neutral-50)); - font-family: var(--font-sans); - gap: var(--space-4); - border-top: 1px solid var(--variant-border, var(--neutral-700)); - transition: background-color var(--transition-colors), box-shadow var(--transition-all); - z-index: var(--z-10); - width: 100%; -} - -/* Footer Position: Sticky Bottom */ -.kroma-footer[data-stick="bottom"] { - position: sticky; - bottom: 0; -} - -/* Footer Position: Fixed Bottom */ -.kroma-footer[data-stick="fixed"] { - position: fixed; - bottom: 0; - left: 0; - width: 100%; - box-shadow: var(--shadow-lg); -} - -/* Footer Layouts */ -.kroma-footer[data-layout="center"] { - flex-direction: column; - text-align: center; - gap: var(--space-4); -} - -.kroma-footer[data-layout="stacked"] { - flex-direction: column; - align-items: flex-start; - gap: var(--space-6); -} - -/* Footer Links */ -.kroma-footer-links { - display: flex; - flex-wrap: wrap; - justify-content: center; - gap: var(--space-4); -} - -.kroma-footer-link { - color: inherit; - text-decoration: none; - font-size: clamp(0.875rem, 1vw, 1rem); - font-weight: 500; - transition: color var(--transition-colors); -} - -.kroma-footer-link:hover, -.kroma-footer-link:focus { - color: var(--variant-hover-bg, var(--neutral-300)); - text-decoration: underline; -} - -/* Footer Brand Section */ -.kroma-footer-brand { - display: flex; - align-items: center; - gap: var(--space-3); - font-size: clamp(1.25rem, 2.5vw, 1.75rem); - font-weight: bold; -} - -.kroma-footer-logo { - max-height: 50px; - object-fit: contain; -} - -/* Footer Copyright Section */ -.kroma-footer-copyright { - font-size: clamp(0.75rem, 1vw, 0.875rem); - color: var(--neutral-400); - margin-top: var(--space-4); - text-align: center; - width: 100%; -} - -/* Footer Social Links */ -.kroma-footer-social { - display: flex; - justify-content: center; - gap: var(--space-3); -} - -.kroma-footer-social a { - font-size: 1.5rem; - color: inherit; - transition: color var(--transition-colors); -} - -.kroma-footer-social a:hover, -.kroma-footer-social a:focus { - color: var(--variant-hover-bg, var(--neutral-300)); -} - -/* Responsive Adjustments */ -@media (max-width: 768px) { - .kroma-footer { - flex-direction: column; - text-align: center; - gap: var(--space-6); - padding: var(--space-4); - } - - .kroma-footer-links, - .kroma-footer-social { - justify-content: center; - gap: var(--space-3); - } - - .kroma-footer-copyright { - margin-top: var(--space-6); - } -} - - /* --- form.css --- */ /* Base Form Group Styling */ .kroma-form-group { @@ -3705,37 +3592,41 @@ blockquote { .kroma-navbar .nav-logo img { width: auto; height: 100%; + min-width: min-content; } .kroma-navbar .nav-logo { - height: calc(var(--nav-size-base) / 1.5 ); - width: min-content; - display: flex; - flex-direction: row; - flex-wrap: nowrap; - align-items: center; - gap: calc(var(--nav-size-base) / 6); + height: calc(var(--nav-size-base) / 1.5 ); + width: max-content; + display: flex; + flex-direction: row; + flex-wrap: nowrap; + align-items: center; + gap: calc(var(--nav-size-base) / 6); + flex: auto; } nav.kroma-navbar { - width: 100%; - height: var(--nav-size-base); - position: sticky; - top: 0; - left: 0; - z-index: 3; - display: flex; - flex-direction: row; - align-content: center; - align-items: center; - flex-wrap: nowrap; - backdrop-filter: blur(4px); - -webkit-backdrop-filter: blur(4px); - justify-content: space-between; - box-sizing: border-box; - padding: calc(var(--nav-size-base) / 6); + width: 100%; + height: var(--nav-size-base); + position: sticky; + top: 0; + left: 0; + z-index: 3; + display: flex; + flex-direction: row; + align-content: center; + align-items: center; + flex-wrap: nowrap; + backdrop-filter: blur(4px); + -webkit-backdrop-filter: blur(4px); + justify-content: space-between; + box-sizing: border-box; + padding: calc(var(--nav-size-base) / 6); + gap: calc(var(--nav-size-base) / 6); } + nav.kroma-navbar:before { content: ""; display: block; @@ -3778,74 +3669,114 @@ nav.kroma-navbar:before { gap: 0; } +nav.kroma-navbar:not(.toggled-menu) .nav-toggle { + display: none; +} + .kroma-navbar .nav-toggle.show #nav-line-3 { - opacity: 0; - /* top: 20px; */ - height: 0; + opacity: 0; + /* top: 20px; */ + height: 0; } .kroma-navbar .nav-toggle.show #nav-line-1 { - transform: translate(0px, 50%) rotate(45deg); - transform-origin: center; + transform: translate(0px, 50%) rotate(45deg); + transform-origin: center; } .kroma-navbar .nav-toggle.show #nav-line-2 { - /* background: var(--neutral-700); */ - transform: translate(0px, -50%) rotate(-45deg); - transform-origin: center; + /* background: var(--neutral-700); */ + transform: translate(0px, -50%) rotate(-45deg); + transform-origin: center; } -.kroma-navbar .nav-menu { - display: flex; - position: absolute; - top: 100%; - right: 0; - margin: calc(var(--nav-size-base) / 3); - background: var(--neutral-50); - border-radius: 10px; - box-shadow: var(--shadow-sm); - align-items: center; - justify-content: center; - /* min-width: 170px; */ - max-height: 0; - opacity: 0; - overflow: hidden; - transition: opacity 100ms, max-height 2s 0ms; +.kroma-navbar.toggled-menu .nav-menu { + display: flex; + position: absolute; + top: 100%; + right: 0; + margin: calc(var(--nav-size-base) / 3); + background: var(--neutral-50); + border-radius: 10px; + box-shadow: var(--shadow-sm); + align-items: center; + justify-content: center; + /* min-width: 170px; */ + max-height: 0; + opacity: 0; + overflow: hidden; + transition: opacity 100ms, max-height 2s 0ms; } -.kroma-navbar .nav-menu ul li a { - text-decoration: none; - list-style: none; - padding: calc(var(--nav-size-base) / 6) calc(var(--nav-size-base) / 1.5); - display: block; +.kroma-navbar.toggled-menu .nav-menu ul li a { + text-decoration: none; + list-style: none; + padding: calc(var(--nav-size-base) / 6) calc(var(--nav-size-base) / 1.5); + display: block; } -.kroma-navbar .nav-menu ul { - width: 100%; - height: 100%; - display: flex; - flex-direction: column; +.kroma-navbar.toggled-menu .nav-menu ul { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; } .kroma-navbar .nav-toggle.show ~ .nav-menu { - max-height: 1000px; - opacity: 1; - transition: max-height 0s 0ms, opacity 100ms; + max-height: 1000px; + opacity: 1; + transition: max-height 0s 0ms, opacity 100ms; } -.kroma-navbar .nav-menu ul li:first-child a { - padding-top: calc(var(--nav-size-base) / 3); +.kroma-navbar.toggled-menu .nav-menu ul li:first-child a { + padding-top: calc(var(--nav-size-base) / 3); } -.kroma-navbar .nav-menu ul li:last-child a { - padding-bottom: calc(var(--nav-size-base) / 3); +.kroma-navbar.toggled-menu .nav-menu ul li:last-child a { + padding-bottom: calc(var(--nav-size-base) / 3); } -.kroma-navbar .nav-menu ul li a.nav-current,.nav-menu ul li:hover a { - background: var(--neutral-100); +.kroma-navbar.toggled-menu .nav-menu ul li:hover +,.kroma-navbar.toggled-menu .nav-menu ul li.nav-current{ +background: var(--neutral-200); } +.kroma-navbar.toggled-menu .nav-menu ul li:hover a +,.kroma-navbar.toggled-menu .nav-menu ul li.nav-current a{ +color: var(--neutral-800); +} + +.nav-menu ul li:hover a { + background: transparent; +} + +nav.kroma-navbar[data-variant]:before { + background: var(--variant-bg); + border-bottom-color: var(--variant-border); +} + +nav.kroma-navbar[data-variant] .nav-logo span, nav.kroma-navbar[data-variant] .nav-menu ul li a { + color: var(--variant-text); +} + + +.kroma-navbar[data-variant] span.nav-line { + background: var(--variant-text); +} + +.kroma-navbar[data-variant].toggled-menu .nav-menu ul li:hover +,.kroma-navbar[data-variant].toggled-menu .nav-menu ul li.nav-current{ +background: var(--variant-hover-bg); +} + +.kroma-navbar[data-variant].toggled-menu .nav-menu ul li:hover a +,.kroma-navbar[data-variant].toggled-menu .nav-menu ul li.nav-current a{ +color: var(--variant-hover); +} + + + /* --- pagination.css --- */ /* Pagination Container */ .kroma-pagination { @@ -4299,7 +4230,7 @@ nav.kroma-navbar:before { /* --- sidebar.css --- */ :root { - --sdb-size-base: calc(clamp(300px,30vw,350px) * 1.2); + --sdb-size-base: calc(clamp(300px,30vw,350px) * 1.1); } /*TEMPORARY FIX FOR SIDEBAR SPACING*/ @@ -4442,6 +4373,10 @@ html:has(.kroma-navbar) .kroma-sidebar{ background: var(--neutral-300); } +.kroma-sidebar.collapsed .sdb-logo:not(:has(img)):after { + display: none; +} + .kroma-sidebar .sdb-logo span { margin: auto 0; } @@ -4546,6 +4481,63 @@ html:has(.kroma-navbar) .kroma-sidebar{ background: #ffffff0f; } +.kroma-sidebar li{ + + cursor:pointer; + + } + +.kroma-sidebar:not(.collapsed) li[data-idparent] { + padding-left: 10px; + max-height: 100px; + transition: 100ms; +} + +.kroma-sidebar:not(.collapsed) li.parent a span:before { + content: "\f054"; + margin-right: 10px; + font-family: 'FontAwesome'; + display: inline-block; +} + +.kroma-sidebar li[data-idparent].collapsed { + max-height: 0; + overflow: hidden; +} + +.kroma-sidebar li.parent:not(.collapsed) a span:before { + transform: rotate(90deg); + transform-origin: center; +} + + +/*variants*/ + +.kroma-sidebar[data-variant]:before { + background: var(--variant-bg); + border-color: var(--variant-border); +} + +.kroma-sidebar[data-variant] .sdb-logo:after{ + background: var(--variant-border); +} + +.kroma-sidebar[data-variant] .sdb-logo span, +.kroma-sidebar[data-variant] .sdb-menu ul li i, +.kroma-sidebar[data-variant] .sdb-menu ul li span, +.kroma-sidebar[data-variant] .sdb-arrow{ + color: var(--variant-text); +} + +.kroma-sidebar[data-variant] .sdb-menu ul li a:hover:before{ + background: var(--variant-hover-bg); +} + +.kroma-sidebar[data-variant] .sdb-menu ul li a:hover > i, +.kroma-sidebar[data-variant] .sdb-menu ul li a:hover > span { + color: var(--variant-hover); +} + /* --- skeleton.css --- */ /* Base Skeleton Container */ .kroma-skeleton { diff --git a/src/css/components/navbar.css b/src/css/components/navbar.css index fb3d993..743405f 100644 --- a/src/css/components/navbar.css +++ b/src/css/components/navbar.css @@ -5,37 +5,41 @@ .kroma-navbar .nav-logo img { width: auto; height: 100%; + min-width: min-content; } .kroma-navbar .nav-logo { - height: calc(var(--nav-size-base) / 1.5 ); - width: min-content; - display: flex; - flex-direction: row; - flex-wrap: nowrap; - align-items: center; - gap: calc(var(--nav-size-base) / 6); + height: calc(var(--nav-size-base) / 1.5 ); + width: max-content; + display: flex; + flex-direction: row; + flex-wrap: nowrap; + align-items: center; + gap: calc(var(--nav-size-base) / 6); + flex: auto; } nav.kroma-navbar { - width: 100%; - height: var(--nav-size-base); - position: sticky; - top: 0; - left: 0; - z-index: 3; - display: flex; - flex-direction: row; - align-content: center; - align-items: center; - flex-wrap: nowrap; - backdrop-filter: blur(4px); - -webkit-backdrop-filter: blur(4px); - justify-content: space-between; - box-sizing: border-box; - padding: calc(var(--nav-size-base) / 6); + width: 100%; + height: var(--nav-size-base); + position: sticky; + top: 0; + left: 0; + z-index: 3; + display: flex; + flex-direction: row; + align-content: center; + align-items: center; + flex-wrap: nowrap; + backdrop-filter: blur(4px); + -webkit-backdrop-filter: blur(4px); + justify-content: space-between; + box-sizing: border-box; + padding: calc(var(--nav-size-base) / 6); + gap: calc(var(--nav-size-base) / 6); } + nav.kroma-navbar:before { content: ""; display: block; @@ -78,70 +82,109 @@ nav.kroma-navbar:before { gap: 0; } +nav.kroma-navbar:not(.toggled-menu) .nav-toggle { + display: none; +} + .kroma-navbar .nav-toggle.show #nav-line-3 { - opacity: 0; - /* top: 20px; */ - height: 0; + opacity: 0; + /* top: 20px; */ + height: 0; } .kroma-navbar .nav-toggle.show #nav-line-1 { - transform: translate(0px, 50%) rotate(45deg); - transform-origin: center; + transform: translate(0px, 50%) rotate(45deg); + transform-origin: center; } .kroma-navbar .nav-toggle.show #nav-line-2 { - /* background: var(--neutral-700); */ - transform: translate(0px, -50%) rotate(-45deg); - transform-origin: center; + /* background: var(--neutral-700); */ + transform: translate(0px, -50%) rotate(-45deg); + transform-origin: center; } -.kroma-navbar .nav-menu { - display: flex; - position: absolute; - top: 100%; - right: 0; - margin: calc(var(--nav-size-base) / 3); - background: var(--neutral-50); - border-radius: 10px; - box-shadow: var(--shadow-sm); - align-items: center; - justify-content: center; - /* min-width: 170px; */ - max-height: 0; - opacity: 0; - overflow: hidden; - transition: opacity 100ms, max-height 2s 0ms; +.kroma-navbar.toggled-menu .nav-menu { + display: flex; + position: absolute; + top: 100%; + right: 0; + margin: calc(var(--nav-size-base) / 3); + background: var(--neutral-50); + border-radius: 10px; + box-shadow: var(--shadow-sm); + align-items: center; + justify-content: center; + /* min-width: 170px; */ + max-height: 0; + opacity: 0; + overflow: hidden; + transition: opacity 100ms, max-height 2s 0ms; } -.kroma-navbar .nav-menu ul li a { - text-decoration: none; - list-style: none; - padding: calc(var(--nav-size-base) / 6) calc(var(--nav-size-base) / 1.5); - display: block; +.kroma-navbar.toggled-menu .nav-menu ul li a { + text-decoration: none; + list-style: none; + padding: calc(var(--nav-size-base) / 6) calc(var(--nav-size-base) / 1.5); + display: block; } -.kroma-navbar .nav-menu ul { - width: 100%; - height: 100%; - display: flex; - flex-direction: column; +.kroma-navbar.toggled-menu .nav-menu ul { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; } .kroma-navbar .nav-toggle.show ~ .nav-menu { - max-height: 1000px; - opacity: 1; - transition: max-height 0s 0ms, opacity 100ms; + max-height: 1000px; + opacity: 1; + transition: max-height 0s 0ms, opacity 100ms; +} + +.kroma-navbar.toggled-menu .nav-menu ul li:first-child a { + padding-top: calc(var(--nav-size-base) / 3); +} + +.kroma-navbar.toggled-menu .nav-menu ul li:last-child a { + padding-bottom: calc(var(--nav-size-base) / 3); +} + +.kroma-navbar.toggled-menu .nav-menu ul li:hover +,.kroma-navbar.toggled-menu .nav-menu ul li.nav-current{ +background: var(--neutral-200); +} + +.kroma-navbar.toggled-menu .nav-menu ul li:hover a +,.kroma-navbar.toggled-menu .nav-menu ul li.nav-current a{ +color: var(--neutral-800); +} + +.nav-menu ul li:hover a { + background: transparent; +} + +nav.kroma-navbar[data-variant]:before { + background: var(--variant-bg); + border-bottom-color: var(--variant-border); +} + +nav.kroma-navbar[data-variant] .nav-logo span, nav.kroma-navbar[data-variant] .nav-menu ul li a { + color: var(--variant-text); +} + + +.kroma-navbar[data-variant] span.nav-line { + background: var(--variant-text); } -.kroma-navbar .nav-menu ul li:first-child a { - padding-top: calc(var(--nav-size-base) / 3); +.kroma-navbar[data-variant].toggled-menu .nav-menu ul li:hover +,.kroma-navbar[data-variant].toggled-menu .nav-menu ul li.nav-current{ +background: var(--variant-hover-bg); } -.kroma-navbar .nav-menu ul li:last-child a { - padding-bottom: calc(var(--nav-size-base) / 3); +.kroma-navbar[data-variant].toggled-menu .nav-menu ul li:hover a +,.kroma-navbar[data-variant].toggled-menu .nav-menu ul li.nav-current a{ +color: var(--variant-hover); } -.kroma-navbar .nav-menu ul li a.nav-current,.nav-menu ul li:hover a { - background: var(--neutral-100); -} \ No newline at end of file diff --git a/src/css/components/sidebar.css b/src/css/components/sidebar.css index 4c51665..529d48b 100644 --- a/src/css/components/sidebar.css +++ b/src/css/components/sidebar.css @@ -1,5 +1,5 @@ :root { - --sdb-size-base: calc(clamp(300px,30vw,350px) * 1.2); + --sdb-size-base: calc(clamp(300px,30vw,350px) * 1.1); } /*TEMPORARY FIX FOR SIDEBAR SPACING*/ @@ -142,6 +142,10 @@ html:has(.kroma-navbar) .kroma-sidebar{ background: var(--neutral-300); } +.kroma-sidebar.collapsed .sdb-logo:not(:has(img)):after { + display: none; +} + .kroma-sidebar .sdb-logo span { margin: auto 0; } @@ -244,4 +248,61 @@ html:has(.kroma-navbar) .kroma-sidebar{ .dark-mode .kroma-sidebar .sdb-menu ul li a:hover:before { background: #ffffff0f; +} + +.kroma-sidebar li{ + + cursor:pointer; + + } + +.kroma-sidebar:not(.collapsed) li[data-idparent] { + padding-left: 10px; + max-height: 100px; + transition: 100ms; +} + +.kroma-sidebar:not(.collapsed) li.parent a span:before { + content: "\f054"; + margin-right: 10px; + font-family: 'FontAwesome'; + display: inline-block; +} + +.kroma-sidebar li[data-idparent].collapsed { + max-height: 0; + overflow: hidden; +} + +.kroma-sidebar li.parent:not(.collapsed) a span:before { + transform: rotate(90deg); + transform-origin: center; +} + + +/*variants*/ + +.kroma-sidebar[data-variant]:before { + background: var(--variant-bg); + border-color: var(--variant-border); +} + +.kroma-sidebar[data-variant] .sdb-logo:after{ + background: var(--variant-border); +} + +.kroma-sidebar[data-variant] .sdb-logo span, +.kroma-sidebar[data-variant] .sdb-menu ul li i, +.kroma-sidebar[data-variant] .sdb-menu ul li span, +.kroma-sidebar[data-variant] .sdb-arrow{ + color: var(--variant-text); +} + +.kroma-sidebar[data-variant] .sdb-menu ul li a:hover:before{ + background: var(--variant-hover-bg); +} + +.kroma-sidebar[data-variant] .sdb-menu ul li a:hover > i, +.kroma-sidebar[data-variant] .sdb-menu ul li a:hover > span { + color: var(--variant-hover); } \ No newline at end of file diff --git a/src/css/utils/display.css b/src/css/utils/display.css index afa8faf..457cee8 100644 --- a/src/css/utils/display.css +++ b/src/css/utils/display.css @@ -2,3 +2,20 @@ .block { display: block; } .inline-block { display: inline-block; } .inline { display: inline; } + + +/*REMOVE HIGHLIGHT BACKGROUND*/ +.no-selection::selection { + background: transparent; + color: inherit; +} + +.no-selection::-moz-selection { + background: transparent; + color: inherit; +} + +.no-selection { + user-select: none; +} + diff --git a/src/js/bundle.js b/src/js/bundle.js index 67e36dc..ea0769d 100644 --- a/src/js/bundle.js +++ b/src/js/bundle.js @@ -3,7 +3,7 @@ Project: kromacss Version: 1.0.2 Description: A modern, lightweight, and dependency-free CSS framework designed for simplicity, speed, and adaptability. Author: Altxria Inc. -License: MIT +License: CC BY-ND 4.0 */ /* --- accordion.js --- */ @@ -181,7 +181,7 @@ function handleAlertClose(alert) { /* --- calendar.js --- */ -export function initializeCalendarComponents() { +function initializeCalendarComponents() { document.querySelectorAll('.kroma-calendar').forEach(initCalendar); } @@ -370,7 +370,7 @@ document.addEventListener('DOMContentLoaded', () => { initializeCodeblock(document); }); -export function initializeCodeblock() { +function initializeCodeblock() { document.querySelectorAll('.kroma-code-block').forEach((block) => { // Check if buttons are already rendered to avoid duplication if (block.querySelector('.kroma-code-block-header')) return; @@ -434,7 +434,7 @@ document.addEventListener('DOMContentLoaded', () => { initializeCommandPalettes(); }); -export function initializeCommandPalettes() { +function initializeCommandPalettes() { // Select all command palettes on the page const palettes = document.querySelectorAll('.kroma-command-palette'); @@ -615,7 +615,7 @@ function initializeCommandPalette(palette) { /* --- datetime-picker.js --- */ -export class DateTimePicker { +class DateTimePicker { constructor(elementId, { format = 'YYYY-MM-DD HH:mm', includeTime = true, variant = 'primary' } = {}) { this.container = document.getElementById(elementId); this.format = format; @@ -945,7 +945,7 @@ document.addEventListener('DOMContentLoaded', () => { /* --- file-upload.js --- */ -export function initializeKromaFileUploadComponents() { +function initializeKromaFileUploadComponents() { document.querySelectorAll('.kroma-file-upload').forEach((fileUpload) => { const dropzone = fileUpload.querySelector('.kroma-file-upload-dropzone'); const input = fileUpload.querySelector('.kroma-file-upload-input'); @@ -1017,7 +1017,7 @@ document.addEventListener('DOMContentLoaded', initializeKromaFileUploadComponent /* --- hologram.js --- */ -export function showHologram(titleText, subtitleText, variant = 'primary', intensity = 'medium', duration = 6000) { +function showHologram(titleText, subtitleText, variant = 'primary', intensity = 'medium', duration = 6000) { // Remove any existing holograms and dim overlay document.querySelectorAll('.kroma-hologram-overlay, .kroma-body-dim').forEach(el => el.remove()); @@ -1238,7 +1238,7 @@ document.addEventListener('DOMContentLoaded', () => { /* --- navbar.js --- */ -export class KromaNavbar { +class KromaNavbar { /* id (string) = navbar element id @@ -1257,6 +1257,12 @@ export class KromaNavbar { About Contacts + +
+ + User Avatar +
+ */ @@ -1274,13 +1280,16 @@ export class KromaNavbar { this.hasLogo = (this.nav.querySelector('img') && this.nav.querySelector('img').src) ? true : false; this.logoPath = this.hasLogo ? this.nav.querySelector('img').src : undefined; this.siteTitle = document.querySelector('head title'); - this.siteTitle = siteTitle ?? (this.siteTitle.innerText ?? ''); + this.siteTitle = ( this.nav.dataset.title ?? siteTitle ) ?? (this.siteTitle.innerText ?? ''); + //menu sizing for toggle + this.menuExtWidth = undefined; + this.menuIntWidth = undefined; //get menu items - this.hasMenu = this.nav.querySelector('a') ? true : false; + this.hasMenu = document.querySelector('#'+this.nav.id+' > a') ? true : false; this.pages = []; - this.nav.querySelectorAll('a').forEach((a)=>{ + this.nav.querySelectorAll('#'+this.nav.id+' > a').forEach((a)=>{ var page = {}; page.href = a.href ?? ''; @@ -1290,6 +1299,10 @@ export class KromaNavbar { }); + //get avatar element + this.hasAvatar = (this.nav.querySelectorAll('.kroma-avatar')).length > 0 ? true : false; + this.avatar = this.hasAvatar ? this.nav.querySelectorAll('.kroma-avatar')[0].cloneNode(true) : undefined; + //remove anything else in navbar container this.nav.innerHTML = ""; @@ -1301,10 +1314,26 @@ export class KromaNavbar { this.addToggle(); this.addMenu(); + this.autoToggle(); + //auto add/remove toggle for menu width + window.addEventListener('resize', () => { + clearTimeout(this.resizeTimeout); + this.resizeTimeout = setTimeout(() => { this.autoToggle(); this.addUpdAvatar(); }, 200); + }); } + + //add avatar + this.addUpdAvatar(); + + + + + + + } @@ -1333,54 +1362,113 @@ export class KromaNavbar { } - addToggle(){ - var toggle = document.createElement('div'); - + if(this.hasMenu){ + + var toggle = document.createElement('div'); + + + toggle.classList.add('nav-toggle'); + toggle.addEventListener('click',function(){if(this.classList.contains('show')){this.classList.remove('show');}else{this.classList.add('show');}}); + + for(var i = 1; i <= 3; i++){ - toggle.classList.add('nav-toggle'); - toggle.addEventListener('click',function(){if(this.classList.contains('show')){this.classList.remove('show');}else{this.classList.add('show');}}); + var line = document.createElement('span'); + line.id = ('nav-line-'+i); + line.classList.add('nav-line'); + toggle.appendChild(line); - for(var i = 1; i <= 3; i++){ + } - var line = document.createElement('span'); - line.id = ('nav-line-'+i); - line.classList.add('nav-line'); - toggle.appendChild(line); + this.nav.appendChild(toggle); + return true; + } - this.nav.appendChild(toggle); + return false; } addMenu(){ - var menu = document.createElement('div'); - menu.classList.add('nav-menu'); - var ul = document.createElement('ul'); - - for(var i = 0; i < this.pages.length; i++){ + if(this.hasMenu){ - var li = document.createElement('li'); - var a = document.createElement('a'); - if(this.pages[i].href.length > 0){ a.href = this.pages[i].href; } - a.innerText = this.pages[i].text; - li.appendChild(a); - ul.appendChild(li); + var menu = document.createElement('div'); + menu.classList.add('nav-menu'); + var ul = document.createElement('ul'); + + for(var i = 0; i < this.pages.length; i++){ + + var li = document.createElement('li'); + var a = document.createElement('a'); + if(this.pages[i].href.length > 0){ a.href = this.pages[i].href; } + a.innerText = this.pages[i].text; + li.appendChild(a); + ul.appendChild(li); + + } + + menu.appendChild(ul); + this.nav.appendChild(menu); + + return true; } - menu.appendChild(ul); - this.nav.appendChild(menu); + return false; + + + } + + autoToggle(){ + if(this.hasMenu){ + + if(window.innerWidth <= 500){this.nav.classList.add('toggled-menu'); return true;} //always add toggle on mobile + this.nav.classList.remove('toggled-menu'); //always use full width navbar for calculations + var menu = document.querySelector('#'+this.nav.id+' .nav-menu'); + if(!menu){console.error('menu container not found'); return false;} + var ul = menu.querySelector(' ul'); + if(!ul){console.error('menu ul not found'); return false;} + this.menuExtWidth = parseInt(getComputedStyle(menu).width); + this.menuIntWidth = parseInt(getComputedStyle(ul).width); + if(!this.menuExtWidth || !this.menuIntWidth){console.error('menu size cannot be determined'); return false;} + if(this.menuExtWidth <= this.menuIntWidth){this.nav.classList.add('toggled-menu'); return true;} + + } + + return false; } + addUpdAvatar(){ + + if(this.hasAvatar){ + + //remove previous avatar + var prevAvatar = this.nav.querySelector('.kroma-avatar'); + if(prevAvatar){prevAvatar.remove();} + + //add avatar before toggle + if(this.nav.classList.contains('toggled-menu')){ + + this.nav.insertBefore(this.avatar, this.nav.querySelector('.nav-toggle')); + return true; + } + + //add avatar at the end + this.nav.appendChild(this.avatar); + + } + + return false; + + } } @@ -1402,7 +1490,7 @@ document.addEventListener("DOMContentLoaded", () => { }); /* --- rating.js --- */ -export function initializeKromaRatingComponents() { +function initializeKromaRatingComponents() { // Automatically initialize all rating components on the page document.querySelectorAll('.kroma-rating').forEach(initializeRatingComponent); } @@ -1452,7 +1540,7 @@ document.addEventListener("DOMContentLoaded", initializeKromaRatingComponents); /* --- sidebar.js --- */ -export class KromaSidebar { +class KromaSidebar { /* id (string) = navbar element id @@ -1509,7 +1597,7 @@ export class KromaSidebar { page.text = a.innerText ?? 'Page'; page.title = page.text; page.icon = a.previousElementSibling; - if( (page.icon.tagName ?? '') != 'I' ){ + if(!page.icon || (page.icon.tagName ?? '') != 'I' ){ page.icon = document.createElement('i'); page.icon.classList.add('fa-solid'); page.icon.classList.add('fa-link'); @@ -1592,6 +1680,8 @@ export class KromaSidebar { for(var i = 0; i < this.pages.length; i++){ var li = document.createElement('li'); + li.querySelector('a').removeAttribute('href'); //remove href from collapsable parent + li.classList.add('no-selection'); //parent page if(!this.pages[i].isChild){ @@ -1633,6 +1723,36 @@ export class KromaSidebar { menu.appendChild(ul); this.sdb.appendChild(menu); + //remove parent class from childless links + document.querySelectorAll('#'+this.sdb.id+' .sdb-menu ul li.parent').forEach((li)=>{ + var liChildren = document.querySelectorAll('#'+this.sdb.id+' .sdb-menu ul li[data-idparent="'+li.dataset.myid+'"]'); + if(liChildren.length < 1){li.classList.remove('parent');} + else{ + li.classList.add('collapsed'); + li.addEventListener('click',function(){ + + var sdbId = this.closest('.kroma-sidebar').id; + var liChildren = document.querySelectorAll('#'+sdbId+' .sdb-menu ul li[data-idparent="'+this.dataset.myid+'"]'); + + if(this.classList.contains('collapsed')){ + this.classList.remove('collapsed'); + liChildren.forEach(function(liChild){ liChild.classList.remove('collapsed'); }); + } + else{ + this.classList.add('collapsed'); + liChildren.forEach(function(liChild){ liChild.classList.add('collapsed'); }); + } + + }); + + } + }); + + //collapse all children links + document.querySelectorAll('#'+this.sdb.id+' .sdb-menu ul li[data-idparent]').forEach((li)=>{ + li.classList.add('collapsed'); + }); + } @@ -1662,7 +1782,7 @@ document.addEventListener("DOMContentLoaded", () => { /* --- slideshow.js --- */ -export class KromaSlideshow { +class KromaSlideshow { /* id (string) = slideshow element id @@ -1964,7 +2084,7 @@ document.addEventListener("DOMContentLoaded", () => { /* --- tabs.js --- */ -export function toggleTabContent(event, contentId, containerId) { +function toggleTabContent(event, contentId, containerId) { const container = document.getElementById(containerId); const tabs = container.querySelectorAll('.kroma-tab'); const contents = container.querySelectorAll('.kroma-tab-content'); @@ -1984,7 +2104,7 @@ export function toggleTabContent(event, contentId, containerId) { /* --- toast.js --- */ -export function initializeKromaToastComponents() { +function initializeKromaToastComponents() { // Automatically initialize and track toast components document.querySelectorAll('.kroma-toast').forEach((toast) => { if (toast.dataset.autoDismiss === "true") { @@ -1994,7 +2114,7 @@ export function initializeKromaToastComponents() { }); } -export function showKromaToast(message, { +function showKromaToast(message, { variant = 'primary', position = 'top-right', autoDismiss = false, diff --git a/src/js/components/calendar.js b/src/js/components/calendar.js index ac5be36..a4bad91 100644 --- a/src/js/components/calendar.js +++ b/src/js/components/calendar.js @@ -1,4 +1,4 @@ -export function initializeCalendarComponents() { +function initializeCalendarComponents() { document.querySelectorAll('.kroma-calendar').forEach(initCalendar); } diff --git a/src/js/components/codeblock.js b/src/js/components/codeblock.js index 4b05b0e..1cc6381 100644 --- a/src/js/components/codeblock.js +++ b/src/js/components/codeblock.js @@ -2,7 +2,7 @@ document.addEventListener('DOMContentLoaded', () => { initializeCodeblock(document); }); -export function initializeCodeblock() { +function initializeCodeblock() { document.querySelectorAll('.kroma-code-block').forEach((block) => { // Check if buttons are already rendered to avoid duplication if (block.querySelector('.kroma-code-block-header')) return; diff --git a/src/js/components/command-palette.js b/src/js/components/command-palette.js index d60cf0f..9c382b1 100644 --- a/src/js/components/command-palette.js +++ b/src/js/components/command-palette.js @@ -2,7 +2,7 @@ document.addEventListener('DOMContentLoaded', () => { initializeCommandPalettes(); }); -export function initializeCommandPalettes() { +function initializeCommandPalettes() { // Select all command palettes on the page const palettes = document.querySelectorAll('.kroma-command-palette'); diff --git a/src/js/components/datetime-picker.js b/src/js/components/datetime-picker.js index e8f4fb0..a875da9 100644 --- a/src/js/components/datetime-picker.js +++ b/src/js/components/datetime-picker.js @@ -1,4 +1,4 @@ -export class DateTimePicker { +class DateTimePicker { constructor(elementId, { format = 'YYYY-MM-DD HH:mm', includeTime = true, variant = 'primary' } = {}) { this.container = document.getElementById(elementId); this.format = format; diff --git a/src/js/components/file-upload.js b/src/js/components/file-upload.js index 16ec634..19890d0 100644 --- a/src/js/components/file-upload.js +++ b/src/js/components/file-upload.js @@ -1,4 +1,4 @@ -export function initializeKromaFileUploadComponents() { +function initializeKromaFileUploadComponents() { document.querySelectorAll('.kroma-file-upload').forEach((fileUpload) => { const dropzone = fileUpload.querySelector('.kroma-file-upload-dropzone'); const input = fileUpload.querySelector('.kroma-file-upload-input'); diff --git a/src/js/components/hologram.js b/src/js/components/hologram.js index e2d35ec..5c47737 100644 --- a/src/js/components/hologram.js +++ b/src/js/components/hologram.js @@ -1,4 +1,4 @@ -export function showHologram(titleText, subtitleText, variant = 'primary', intensity = 'medium', duration = 6000) { +function showHologram(titleText, subtitleText, variant = 'primary', intensity = 'medium', duration = 6000) { // Remove any existing holograms and dim overlay document.querySelectorAll('.kroma-hologram-overlay, .kroma-body-dim').forEach(el => el.remove()); diff --git a/src/js/components/navbar.js b/src/js/components/navbar.js index 9029f46..c19389c 100644 --- a/src/js/components/navbar.js +++ b/src/js/components/navbar.js @@ -1,4 +1,4 @@ -export class KromaNavbar { +class KromaNavbar { /* id (string) = navbar element id @@ -17,6 +17,12 @@ export class KromaNavbar { About Contacts + +
+ + User Avatar +
+ */ @@ -34,13 +40,16 @@ export class KromaNavbar { this.hasLogo = (this.nav.querySelector('img') && this.nav.querySelector('img').src) ? true : false; this.logoPath = this.hasLogo ? this.nav.querySelector('img').src : undefined; this.siteTitle = document.querySelector('head title'); - this.siteTitle = siteTitle ?? (this.siteTitle.innerText ?? ''); + this.siteTitle = ( this.nav.dataset.title ?? siteTitle ) ?? (this.siteTitle.innerText ?? ''); + //menu sizing for toggle + this.menuExtWidth = undefined; + this.menuIntWidth = undefined; //get menu items - this.hasMenu = this.nav.querySelector('a') ? true : false; + this.hasMenu = document.querySelector('#'+this.nav.id+' > a') ? true : false; this.pages = []; - this.nav.querySelectorAll('a').forEach((a)=>{ + this.nav.querySelectorAll('#'+this.nav.id+' > a').forEach((a)=>{ var page = {}; page.href = a.href ?? ''; @@ -50,6 +59,10 @@ export class KromaNavbar { }); + //get avatar element + this.hasAvatar = (this.nav.querySelectorAll('.kroma-avatar')).length > 0 ? true : false; + this.avatar = this.hasAvatar ? this.nav.querySelectorAll('.kroma-avatar')[0].cloneNode(true) : undefined; + //remove anything else in navbar container this.nav.innerHTML = ""; @@ -61,10 +74,26 @@ export class KromaNavbar { this.addToggle(); this.addMenu(); + this.autoToggle(); + //auto add/remove toggle for menu width + window.addEventListener('resize', () => { + clearTimeout(this.resizeTimeout); + this.resizeTimeout = setTimeout(() => { this.autoToggle(); this.addUpdAvatar(); }, 200); + }); } + + //add avatar + this.addUpdAvatar(); + + + + + + + } @@ -93,54 +122,113 @@ export class KromaNavbar { } - addToggle(){ - var toggle = document.createElement('div'); - + if(this.hasMenu){ + + var toggle = document.createElement('div'); + - toggle.classList.add('nav-toggle'); - toggle.addEventListener('click',function(){if(this.classList.contains('show')){this.classList.remove('show');}else{this.classList.add('show');}}); + toggle.classList.add('nav-toggle'); + toggle.addEventListener('click',function(){if(this.classList.contains('show')){this.classList.remove('show');}else{this.classList.add('show');}}); - for(var i = 1; i <= 3; i++){ + for(var i = 1; i <= 3; i++){ - var line = document.createElement('span'); - line.id = ('nav-line-'+i); - line.classList.add('nav-line'); - toggle.appendChild(line); + var line = document.createElement('span'); + line.id = ('nav-line-'+i); + line.classList.add('nav-line'); + toggle.appendChild(line); + } + + this.nav.appendChild(toggle); + + return true; + } - this.nav.appendChild(toggle); + return false; } addMenu(){ - var menu = document.createElement('div'); - menu.classList.add('nav-menu'); - var ul = document.createElement('ul'); - - for(var i = 0; i < this.pages.length; i++){ + if(this.hasMenu){ + + var menu = document.createElement('div'); + menu.classList.add('nav-menu'); + var ul = document.createElement('ul'); + + for(var i = 0; i < this.pages.length; i++){ + + var li = document.createElement('li'); + var a = document.createElement('a'); + if(this.pages[i].href.length > 0){ a.href = this.pages[i].href; } + a.innerText = this.pages[i].text; + li.appendChild(a); + ul.appendChild(li); - var li = document.createElement('li'); - var a = document.createElement('a'); - if(this.pages[i].href.length > 0){ a.href = this.pages[i].href; } - a.innerText = this.pages[i].text; - li.appendChild(a); - ul.appendChild(li); + } + + menu.appendChild(ul); + this.nav.appendChild(menu); + + return true; } - menu.appendChild(ul); - this.nav.appendChild(menu); + return false; + + + } + + autoToggle(){ + if(this.hasMenu){ + + if(window.innerWidth <= 500){this.nav.classList.add('toggled-menu'); return true;} //always add toggle on mobile + this.nav.classList.remove('toggled-menu'); //always use full width navbar for calculations + var menu = document.querySelector('#'+this.nav.id+' .nav-menu'); + if(!menu){console.error('menu container not found'); return false;} + var ul = menu.querySelector(' ul'); + if(!ul){console.error('menu ul not found'); return false;} + this.menuExtWidth = parseInt(getComputedStyle(menu).width); + this.menuIntWidth = parseInt(getComputedStyle(ul).width); + if(!this.menuExtWidth || !this.menuIntWidth){console.error('menu size cannot be determined'); return false;} + if(this.menuExtWidth <= this.menuIntWidth){this.nav.classList.add('toggled-menu'); return true;} + + } + + return false; } + addUpdAvatar(){ + if(this.hasAvatar){ + + //remove previous avatar + var prevAvatar = this.nav.querySelector('.kroma-avatar'); + if(prevAvatar){prevAvatar.remove();} + + //add avatar before toggle + if(this.nav.classList.contains('toggled-menu')){ + + this.nav.insertBefore(this.avatar, this.nav.querySelector('.nav-toggle')); + return true; + + } + + //add avatar at the end + this.nav.appendChild(this.avatar); + + } + + return false; + + } } diff --git a/src/js/components/rating.js b/src/js/components/rating.js index 50f19cc..53c0b50 100644 --- a/src/js/components/rating.js +++ b/src/js/components/rating.js @@ -1,4 +1,4 @@ -export function initializeKromaRatingComponents() { +function initializeKromaRatingComponents() { // Automatically initialize all rating components on the page document.querySelectorAll('.kroma-rating').forEach(initializeRatingComponent); } diff --git a/src/js/components/sidebar.js b/src/js/components/sidebar.js index a44d19b..8d67378 100644 --- a/src/js/components/sidebar.js +++ b/src/js/components/sidebar.js @@ -1,4 +1,4 @@ -export class KromaSidebar { +class KromaSidebar { /* id (string) = navbar element id @@ -55,7 +55,7 @@ export class KromaSidebar { page.text = a.innerText ?? 'Page'; page.title = page.text; page.icon = a.previousElementSibling; - if( (page.icon.tagName ?? '') != 'I' ){ + if(!page.icon || (page.icon.tagName ?? '') != 'I' ){ page.icon = document.createElement('i'); page.icon.classList.add('fa-solid'); page.icon.classList.add('fa-link'); @@ -138,6 +138,8 @@ export class KromaSidebar { for(var i = 0; i < this.pages.length; i++){ var li = document.createElement('li'); + li.querySelector('a').removeAttribute('href'); //remove href from collapsable parent + li.classList.add('no-selection'); //parent page if(!this.pages[i].isChild){ @@ -179,6 +181,36 @@ export class KromaSidebar { menu.appendChild(ul); this.sdb.appendChild(menu); + //remove parent class from childless links + document.querySelectorAll('#'+this.sdb.id+' .sdb-menu ul li.parent').forEach((li)=>{ + var liChildren = document.querySelectorAll('#'+this.sdb.id+' .sdb-menu ul li[data-idparent="'+li.dataset.myid+'"]'); + if(liChildren.length < 1){li.classList.remove('parent');} + else{ + li.classList.add('collapsed'); + li.addEventListener('click',function(){ + + var sdbId = this.closest('.kroma-sidebar').id; + var liChildren = document.querySelectorAll('#'+sdbId+' .sdb-menu ul li[data-idparent="'+this.dataset.myid+'"]'); + + if(this.classList.contains('collapsed')){ + this.classList.remove('collapsed'); + liChildren.forEach(function(liChild){ liChild.classList.remove('collapsed'); }); + } + else{ + this.classList.add('collapsed'); + liChildren.forEach(function(liChild){ liChild.classList.add('collapsed'); }); + } + + }); + + } + }); + + //collapse all children links + document.querySelectorAll('#'+this.sdb.id+' .sdb-menu ul li[data-idparent]').forEach((li)=>{ + li.classList.add('collapsed'); + }); + } diff --git a/src/js/components/slideshow.js b/src/js/components/slideshow.js index 2d5687d..c961768 100644 --- a/src/js/components/slideshow.js +++ b/src/js/components/slideshow.js @@ -1,4 +1,4 @@ -export class KromaSlideshow { +class KromaSlideshow { /* id (string) = slideshow element id diff --git a/src/js/components/tabs.js b/src/js/components/tabs.js index eafc678..4b4cf4b 100644 --- a/src/js/components/tabs.js +++ b/src/js/components/tabs.js @@ -1,4 +1,4 @@ -export function toggleTabContent(event, contentId, containerId) { +function toggleTabContent(event, contentId, containerId) { const container = document.getElementById(containerId); const tabs = container.querySelectorAll('.kroma-tab'); const contents = container.querySelectorAll('.kroma-tab-content'); diff --git a/src/js/components/toast.js b/src/js/components/toast.js index d297f4f..7ec94be 100644 --- a/src/js/components/toast.js +++ b/src/js/components/toast.js @@ -1,4 +1,4 @@ -export function initializeKromaToastComponents() { +function initializeKromaToastComponents() { // Automatically initialize and track toast components document.querySelectorAll('.kroma-toast').forEach((toast) => { if (toast.dataset.autoDismiss === "true") { @@ -8,7 +8,7 @@ export function initializeKromaToastComponents() { }); } -export function showKromaToast(message, { +function showKromaToast(message, { variant = 'primary', position = 'top-right', autoDismiss = false,