/********************************************************************** * * * **********************************************************************/ @import '../node_modules/material-symbols/outlined.css'; /********************************************************* Config ****/ :root { /* dimensions */ --gallery-image-base-height: 18rem; --gallery-image-spacing: 0rem; --gallery-current-image-border: 0.7rem; --gallery-padding: 3rem; --gallery-scrollbar-width: 0.5rem; --toolbar-button-size: 2rem; --lightbox-frame: 5vmin; --lightbox-image-margin-top: 0.75; --lightbox-button-size: 2rem; /* theme */ --gallery-text-color: black; --gallery-secondary-color: silver; --gallery-shade-color: whitesmoke; --gallery-background-color: white; --gallery-accent-color: white; --gallery-secondary-accent-color: white; --lightbox-text-color: black; --lightbox-background-color: white; /*--lightbox-background-color: rgba(0,0,0,0.8);*/ --color-transition: 1s; /* base font size... */ /* XXX can we use this as the basis for sizing for different devices??? */ font-size: 5mm; } /* calculated values... */ /* NOTE: these need to be separeated from the :root values to recalculate... */ body { --gallery-image-margin: calc(var(--gallery-image-spacing) / 2); --gallery-padding-horizontal: var(--gallery-padding); --gallery-padding-vertical: var(--gallery-current-image-border); --gallery-padding-top: var(--gallery-padding-vertical); --gallery-padding-bottom: var(--gallery-padding-vertical); --gallery-padding-left: var(--gallery-padding-horizontal); --gallery-padding-right: var(--gallery-padding-horizontal); --gallery-image-scroll-margin: calc(2 * var(--gallery-current-image-border)); --gallery-empty-height: var(--gallery-image-base-height); --scrollbar-color: var(--gallery-secondary-color); } .gallery-dark { --gallery-text-color: silver; --gallery-secondary-color: gray; --gallery-shade-color: rgb(50,50,50); --gallery-background-color: rgb(10,10,10); } .lightbox-dark { --lightbox-text-color: silver; --lightbox-background-color: rgb(10,10,10); } /* XXX to make the lightbox scrolbar work correctly we need to set the * body colors -- :has(..) does not yet work on FF .... */ .lightbox-dark.lightboxed, .lightbox-dark:has(.lightboxed) { --gallery-background-color: var(--lightbox-background-color); --gallery-text-color: var(--lightbox-text-color); overflow: hidden; } /****************************************************** Scrolling ****/ ::-webkit-scrollbar { width: var(--gallery-scrollbar-width); } ::-webkit-scrollbar-track { background-color: transparent; border-radius: 100px; } ::-webkit-scrollbar-thumb { background-color: var(--scrollbar-color); border-radius: 100px; } body { overflow-y: scroll; /* XXX these for some reason do not work in FF... */ scrollbar-width: thin; scrollbar-color: transparent var(--gallery-secondary-color); color: var(--gallery-text-color); background: var(--gallery-background-color); transition: text-shadow var(--color-transition) ease, background var(--color-transition) ease, color var(--color-transition) ease; } button { color: var(--gallery-text-color); background: var(--gallery-background-color); border: solid 1px var(--gallery-secondary-color); transition: text-shadow var(--color-transition) ease, background var(--color-transition) ease, color var(--color-transition) ease; } button:hover { background: var(--gallery-shade-color); border: solid 1px var(--gallery-text-color); } button:active { background: var(--gallery-secondary-color); border: solid 1px var(--gallery-text-color); } /******************************************************** Gallery ****/ /* XXX need to account for scrollbar popping in and out */ .gallery { --base-layer: 10; position: relative; padding-top: var(--gallery-padding-top); padding-bottom: var(--gallery-padding-bottom); padding-left: calc( var(--gallery-scrollbar-width) + var(--gallery-padding-left) ); padding-right: var(--gallery-padding-right); color: var(--gallery-text-color); background: var(--gallery-background-color); font-family: sans-serif; overflow-x: clip; transition: text-shadow var(--color-transition) ease, background var(--color-transition) ease, color var(--color-transition) ease; } .gallery .images { position: relative; display: flex; justify-content: flex-start; align-content: flex-start; flex-flow: row wrap; } /* empty... */ .gallery .images:empty { height: var(--gallery-empty-height); border: dashed 1px var(--gallery-secondary-color); } .gallery .images:empty:after, .gallery .images:empty:before { --font-size: 1.5rem; position: absolute; width: 100%; left: 0; top: 0; line-height: var(--gallery-empty-height); text-align: center; opacity: 0.6; } .gallery .images:empty:before { content: "Empty"; font-size: var(--font-size); } .gallery .images:empty:after { content: "(drag new images here)"; font-size: small; margin-top: calc(var(--font-size) / 1.3); opacity: 0.4; } /* empty otter... */ .gallery.otter .images:empty:before, .gallery.otter .images:empty:after { --font-size: 2em; } .gallery.otter .images:empty:before { content: "🦦"; filter: saturate(0) contrast(200%); } .gallery.otter .images:empty:after { margin-top: calc(var(--font-size) / 1.5); } /* image... */ .gallery .images img { height: var(--gallery-image-base-height); width: auto; border: solid var(--gallery-image-margin) transparent; box-sizing: border-box; scroll-margin: var(--gallery-image-scroll-margin); image-rendering: crisp-edges; cursor: pointer; } .gallery:not(.lightboxed) .images img:not(.current):hover { z-index: calc(var(--base-layer) + 1); outline: solid calc(var(--gallery-current-image-border) / 5) var(--gallery-accent-color); box-shadow: 0.2em 0.2em 1em 0em rgba(0,0,0,0.8); } /* current image... */ .gallery .images img.current { z-index: 10; outline: solid var(--gallery-current-image-border) var(--gallery-accent-color); box-shadow: 0.4em 0.4em 2em 0em rgba(0,0,0,0.8); } .gallery:not(.lightboxed) .images img.current:hover { z-index: calc(var(--base-layer) + 1); outline: solid var(--gallery-current-image-border) var(--gallery-secondary-accent-color); box-shadow: 0.6em 0.6em 3em 0em rgba(0,0,0,0.8); } /* dragged image... */ .gallery .images img.dragged { } .gallery .images:has(.dragged) img:not(.dragged) { } /* image dragged over... */ .gallery.dragged-over .images img { filter: saturate(0) brightness(0.4); } .gallery .images img.dragged-over { z-index: calc(var(--base-layer) + 1); border-left: none; margin-left: var(--gallery-image-margin); box-shadow: calc(var(--gallery-current-image-border) * -1) 0px 0px 0px rgba(0,0,0,0.8), /* XXX this does not work... */ inset var(--gallery-current-image-border) 0px 0px 0px rgba(0,0,0,0.8); } /* image marked for removal... */ .gallery .images img.to-remove { opacity: 0.3; filter: saturate(0); } /*************************************************** Image markers ***/ .gallery .images img+.mark { z-index: var(--base-layer); position: relative; } .gallery .images img:hover+.mark { z-index: calc(var(--base-layer) + 1); } .gallery.lightboxed .images img:not(.current)+.mark { display: none; } .gallery.lightboxed .images img.current+.mark { z-index: calc(var(--base-layer) + 1); position: fixed; bottom: 0; right: 0; } /* marker: marked */ .gallery .images img+.mark.marked:after { content: ""; position: absolute; display: block; width: 1em; height: 1em; right: 0.5em; bottom: 0.5em; border-radius: 50%; background: blue; box-shadow: 0em 0em 0em 0.05em rgba(255,255,255,1); cursor: pointer; } /******************************************************** Toolbar ****/ /* NOTE: this is used as a reference element to place the toolbars * relative to... */ .gallery .toolbar-anchor { position: sticky; top: 0; height: 0; margin: 0 calc(var(--gallery-padding-horizontal) * -1); overflow: visible; z-index: calc(var(--base-layer) + 2); } /* XXX make the toolbar contextual... */ .gallery .toolbar { --move-x: 0; --move-y: 0; --padding: 0.5rem; --height: calc((var(--toolbar-button-size) + var(--padding) * 2)); /*position: absolute;*/ position: relative; display: inline-block; left: var(--move-x); top: var(--move-y); width: fit-content; min-height: var(--toolbar-button-size); margin: 0.1em 0px; padding: var(--padding); padding-right: var(--height); padding-left: var(--height); /*scroll-margin: var(--gallery-image-scroll-margin);*/ translate: 0 0; border: solid 1px var(--gallery-secondary-color); border-radius: calc(var(--height) / 8); background: var(--gallery-background-color); box-shadow: 0.2em 0.2em 0.5em -0.3em rgba(0,0,0,0.8); transition: left 0.2s, padding-right 0.2s, opacity 0.2s, translate 0.2s, text-shadow var(--color-transition) ease, background var(--color-transition) ease, color var(--color-transition) ease; user-select: none; } /* XXX need to hide parts of the toolbar and make it transparent... */ .gallery.lightboxed .toolbar, .gallery.detailed .toolbar { display: none; } /* moving toolbar... */ .gallery .toolbar.moving { transition: none; } /* fixed toolbar... */ .gallery .toolbar.fixed { padding-left: var(--padding); } .gallery .toolbar.fixed .drag-handle { display: none; } /* sticky toolbar indicator... */ .gallery .toolbar.sticky:after { content: "lock"; display: block; position: absolute; bottom: 0; right: 0; padding: calc(var(--toolbar-button-size) / 10); font-family: "Material Symbols Outlined"; font-size: small; font-weight: bold; opacity: 0.3; pointer-events: none; } /* collapsed toolbar (default)... */ /* XXX shoud the toolbar be vertical??? */ .gallery .toolbar:not(.shown) { translate: calc(-100% + var(--toolbar-button-size) + var(--padding) / 2) 0; left: 0; /*padding-right: calc(var(--padding) / 5);*/ padding-right: var(--height); } .gallery .toolbar:not(.shown):not(:hover) { box-shadow: none; z-index: var(--base-layer); animation: 0.5s steps(1) tuck-to-backgroud; } @keyframes tuck-to-backgroud { 0% { z-index: calc(var(--base-layer) + 2); } 100% { z-index: var(--base-layer); } } /* groups... */ .gallery .toolbar>* { display: inline-block; height: calc(100% - var(--padding) * 2); } .gallery .toolbar>*:not(:last-child):after { content: ""; display: inline-block; position: absolute; top: var(--padding); bottom: var(--padding); margin-left: calc(var(--padding) / 4); border-right: solid 1px var(--gallery-secondary-color); } /* state list (group)... */ .gallery .toolbar .states:empty { display: inline-block; } .gallery .toolbar .states:empty:before { content: "Empty..."; font-family: sans-serif; line-height: var(--toolbar-button-size); text-align: center; vertical-align: bottom; padding: 0 0.5em; opacity: 0.3; } /* buttons... */ .gallery .button, .gallery .toolbar button { min-width: var(--toolbar-button-size); border: solid 1px transparent; background: transparent; font-family: "Material Symbols Outlined"; font-size: var(--toolbar-button-size); line-height: var(--toolbar-button-size); font-weight: 300; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-rendering: optimizeLegibility; font-feature-settings: "liga"; text-align: center; color: var(--gallery-text-color); transition: text-shadow var(--color-transition) ease, background var(--color-transition) ease, color var(--color-transition) ease; } .gallery .toolbar button.collapse:after, .gallery .toolbar button sec { display: inline-block; position: relative; left: 0; bottom: calc(var(--toolbar-button-size) / -6); margin-left: calc(var(--toolbar-button-size) / -1.5625); margin-right: -0.15em; font-size: calc(var(--toolbar-button-size) / 1.15); /* XXX HACK: might be better to use SVG for this... */ text-shadow: 0em 0.05em 0px var(--gallery-background-color), 0.05em 0em 0px var(--gallery-background-color), -0.05em 0em 0px var(--gallery-background-color), 0em -0.05em 0px var(--gallery-background-color), 0.05em 0.05em 0px var(--gallery-background-color), -0.05em -0.05em 0px var(--gallery-background-color), -0.05em 0.05em 0px var(--gallery-background-color), 0.05em -0.05em 0px var(--gallery-background-color); transition: text-shadow var(--color-transition) ease, background var(--color-transition) ease, color var(--color-transition) ease; } /* collapse indicator... */ .gallery .toolbar button.collapse:after { content: "keyboard_double_arrow_left"; } .gallery .toolbar button.collapse:after { transition: rotate 0.2s, text-shadow var(--color-transition) ease, background var(--color-transition) ease, color var(--color-transition) ease; } .gallery .toolbar:not(.shown) button.collapse:after { rotate: 180deg; } .gallery .toolbar button:hover { border-radius: calc(var(--toolbar-button-size) / 5); border-color: var(--gallery-secondary-color); } .gallery .toolbar .states button { font-family: sans-serif; line-height: var(--toolbar-button-size); text-align: center; vertical-align: bottom; } /* button: collapse... */ .gallery .toolbar button.collapse { position: absolute; height: 100%; top: 0; right: 0; opacity: 0.4; } .gallery .toolbar button.collapse:hover { opacity: 1; border-color: transparent; } .gallery .toolbar button.drag-handle { position: absolute; height: calc(100% - var(--padding) * 2); top: 0; left: 0; margin-top: var(--padding); margin-bottom: var(--padding); font-family: "Material Symbols Outlined"; font-size: var(--toolbar-button-size); line-height: var(--toolbar-button-size); font-weight: 300; cursor: pointer; color: var(--gallery-secondary-color); } .gallery .toolbar .drag-handle:hover { border-top-color: transparent; border-left-color: transparent; border-bottom-color: transparent; } /******************************************************* Overlays ****/ .gallery.lightboxed, .gallery.detailed { --base-layer: 100; } .gallery.lightboxed .lightbox, .gallery.detailed .details { display: block; } .gallery .lightbox, .gallery .details { display: none; position: fixed; width: 100%; height: 100%; top: 0px; left: 0px; z-index: var(--base-layer); text-align: center; color: var(--gallery-text-color); background: var(--gallery-background-color); } /*------------------------------------------------------ Lightbox ---*/ .gallery .lightbox { color: var(--lightbox-text-color); background: var(--lightbox-background-color); } .gallery .lightbox.show-caption:before { content: attr(caption); position: absolute; bottom: 0.5em; left: 0.5em; } .gallery .lightbox.clickable { cursor: pointer; } /* XXX add metadata display... */ .gallery .lightbox img { object-fit: contain; width: calc( 100vw - var(--lightbox-frame) * 2); height: calc( 100vh - var(--lightbox-frame) * 2); margin-top: calc( var(--lightbox-frame) * var(--lightbox-image-margin-top)); } /*------------------------------------------------------- Details ---*/ .gallery .details img { width: 20em; height: 20em; padding: 0.5em; object-fit: contain; border: solid 1px black; } /******************************************************* Controls ****/ /* XXX these are only used in the lightbox... */ .gallery .buttons { display: flex; position: absolute; top: 0; right: 0; } .gallery .button { disbplay: inline-block; cursor: pointer; width: var(--lightbox-button-size); height: var(--lightbox-button-size); margin: 0.2em; font-size: var(--lightbox-button-size); line-height: var(--lightbox-button-size); color: var(--lightbox-text-color); filter: saturate(0); opacity: 0.1; } .gallery .button:hover { opacity: 1; filter: saturate(1); color: var(--lightbox-text-color); transition: none; } /* specific controls */ .gallery .button.close:after { content: "close"; } .gallery .button.fullscreen:after { content: "fullscreen"; } .gallery .button.info:after { content: "info"; } .gallery .button.prev:after { content: "navigate_before"; } .gallery .button.next:after { content: "navigate_next"; } /********************************************************* Splash ****/ .gallery .loading { position: absolute; display: block; top: 0; left: 0; width: 100%; height:100%; text-align: center; z-index: calc(var(--base-layer) * 2); background: var(--gallery-background-color); opacity: 0.5; } .gallery.ready .loading { animation: fadeOutAnimation ease 2s; animation-iteration-count: 1; animation-fill-mode: forwards; pointer-events: none; } @keyframes fadeOutAnimation { 0% { opacity: 1; } 100% { opacity: 0; visibility: hidden; } } .gallery.ready .loading * { display: none; } /* loading bar animation... */ .gallery .loading>div { --bar-size: 0.2rem; position: sticky; top: var(--bar-size); height: var(--bar-size); background: rgba(0,0,0,0.1); } .gallery .loading>div:before, .gallery .loading>div:after { content: ""; position: absolute; top: 0; left: 0; width: 100%; height: var(--bar-size); background: var(--gallery-text-color); opacity: 0.5; } .gallery .loading>div:after { animation: loadingBarAnimation ease infinite alternate 2s; } .gallery .loading>div:before { width: 50%; animation: loadingBarAnimation ease infinite alternate 1.5s; } @keyframes loadingBarAnimation { 0% { translate: -100%; } 100% { translate: 100%; } } /* loading images animation... */ .gallery:not(.ready) .images .mark { display: none; } .gallery:not(.ready) .images img { --duration: 3s; --delay: 0s; --extend: 1; box-shadow: none; animation: loadingImagesAnimation ease infinite alternate calc(var(--duration) * var(--extend)) var(--delay); } /* variations... */ .gallery .images img:nth-child(2n) { --delay: 0.2s; --extend: 0.9; } .gallery .images img:nth-child(3n) { --delay: 0.5s; --extend: 1.3; } .gallery .images img:nth-child(5n) { --delay: 0.4s; --extend: 1.6; } .gallery .images img:nth-child(7n) { --delay: 0.1s; --extend: 0.6; } @keyframes loadingImagesAnimation { 0% { filter: contrast(0); opacity: 0.2; } 50% { filter: contrast(0); opacity: 0.3; } 100% { filter: contrast(0); opacity: 0.1; } } /********************************************************** Utils ****/ .gallery:not(.lightboxed):not(.detailed) .hide-in-gallery, .gallery.lightboxed .hide-in-lightbox, .gallery.detailed .hide-in-details { display: none; } /********************************************************************** * vim:set ts=4 sw=4 : */