/********************************************************************** * * ********************************************************* Settings ***/ /* XXX might be a good idea to rename this to something more specific like imagegrid-viewer */ .viewer { --image-tile-size: 50vmin; /* gen 2 */ --image-mark-size: calc(var(--image-tile-size) / 60); --image-border: calc(var(--image-tile-size) / 80); --ribbon-margin: calc(var(--image-tile-size) / 30); --ribbon-mark-offset: calc(var(--image-tile-size) / 200); --ribbon-mark-size: calc(var(--image-tile-size) / 30); --single-image-indicator-size: calc(var(--image-tile-size) / 30); } /******************************************************** theaming ***/ .viewer, .viewer.gray { --text-color: white; --background-color: #333; --image-background-color: black; --ribbon-background-color: none; --dialog-background-color: #555; } .viewer.dark { --text-color: white; --background-color: #0a0a0a; --dialog-background-color: #333; } .viewer.light { --text-color: black; --background-color: white; } .viewer.single-image-mode { /* XXX should these be transparent??? */ /* XXX should these be !important??? */ --image-background-color: none !important; --ribbon-background-color: none !important; } /********************************************************* utility ***/ .expanding-text .hidden { display: none; } .expanding-text:hover .shown { display: none; } .expanding-text .shown, .expanding-text:hover .hidden { display: inline; } /* XXX cleanup and style... - make the arrow exact (like in .tooltip-right) - need to align correctly for really narrow elements... */ [tooltip] { position: relative; text-decoration: none; } [tooltip]:after { display: none; content: attr(tooltip); position: absolute; bottom: 130%; left: 20%; background: #ffcb66; padding: 5px 15px; color: black; border-radius: 10px; white-space: pre; text-align: left; font-size: 10px; opacity: 0; -webkit-transition: all 0.4s ease; -moz-transition: all 0.4s ease; transition: all 0.4s ease; } [tooltip]:before { display: none; content: ""; position: absolute; width: 0; height: 0; border-top: 20px solid #ffcb66; border-left: 20px solid transparent; border-right: 20px solid transparent; -webkit-transition: all 0.4s ease; -moz-transition : all 0.4s ease; transition : all 0.4s ease; opacity: 0; left: 30%; bottom: 90%; } [tooltip]:hover:after { display: block; bottom: 100%; } [tooltip]:hover:before { display: block; bottom: 70%; } [tooltip]:hover:after, [tooltip]:hover:before { opacity: 1; } /* make this above everything else... * XXX not sure if this is the best way... */ [tooltip]:hover { z-index: 1000; } .tooltip-right[tooltip] { } .tooltip-right[tooltip]:after { min-height: 30px; bottom: auto; top: -50%; left: 15px; } .tooltip-right[tooltip]:before { border-left: 5px solid transparent; border-right: 5px solid #ffcb66; border-bottom: 5px solid transparent; border-top: 5px solid transparent; bottom: auto; left: 5px; top: 25%; } .tooltip-right[tooltip]:hover:after { bottom: auto; } .tooltip-right[tooltip]:hover:before { bottom: auto; } /* XXX might be good to move this to forms... */ .tooltip-icon { font-size: small; opacity: 0.9; } .cursor-hidden { cursor: none; } .cursor-hidden-r, .cursor-hidden-r * { cursor: none !important; } .blink{ animation: blink 200ms; } @keyframes blink { from { opacity: 1; } to { opacity: 0; } } /*********************************************************************/ .svg-filters { display: none; } :focus { outline: rgba(255, 255, 255, 0.5) 1px solid; } body { font-family: opensans, sans-serif; padding: 0px; margin: 0px; } input, button { border: solid silver 1px; border-radius: 3px; } button:hover { box-shadow: 0px 0px 7px 0px black; } /************************************************************** UI ***/ .title-bar { display: block; position: fixed; content: ""; top: 0px; left: 0px; height: 20px; width: 100%; color: white; background: black; overflow: hidden; opacity: 0; z-index: 10000; /* node-webkit */ -webkit-app-region: drag; } .title-bar:hover { opacity: 1; } .title-bar .title { display: inline-block; float: left; height: 20px; width: auto; color: white; background: transparent; font-size: 11px; font-style: italic; font-weight: bold; vertical-align: middle; text-align: left; margin: 2px; margin-left: 10px; } .title-bar .button { display: inline-block; float: right; width: 20px; height: 20px; color: white; background: transparent; font-size: 18px; vertical-align: middle; /* node-webkit */ -webkit-app-region: no-drag; } .title-bar .button:hover { cursor: pointer; } .title-bar .close:hover { color: red; } .drag-bar { position: absolute; -webkit-app-region: drag; height: 50px; top: 0px; left: 0px; right: 0px; } /* .full-screen-mode .title-bar { display: none; } */ .buttons { display: block; position: relative; float: left; -webkit-app-region: no-drag; size: 30px; cursor: default; z-index: 4000; } /* general button visibility */ .buttons .button { opacity: 0.4; /* XXX not sure about this... */ transition : all 0.1s ease; } .buttons:hover .button { opacity: 0.5; } .buttons .button:hover { opacity: 1; } .buttons .button.visible { opacity: 1 !important; } .light .buttons .button { opacity: 0.5; } .dark .buttons .button { opacity: 0.2; } .buttons .button { display: inline-block; color: silver; box-sizing: border-box; min-width: 40px; height: 40px; padding-left: 5px; padding-right: 5px; text-align: center; line-height: 40px; } .buttons .button:hover { color: white; background: rgba(0, 0, 0, 0.5); } .buttons .button.spacer:hover { background: transparent; } .buttons .button sub { font-size: x-small; } /* Custom buttons... */ /* XXX do we need both this and the active update??? */ /* XXX this seems a bit overcomplicated... */ .crop-mode:not(.slideshow-running) .buttons .button.crop, .collection-mode:not(.slideshow-running) .buttons .button.collections { opacity: 0.7; } .crop-mode:not(.slideshow-running) .buttons:hover .button.crop, .collection-mode:not(.slideshow-running) .buttons:hover .button.collections { opacity: 1; } .single-image-mode:not(.slideshow-running).crop-mode .buttons .button.crop, .single-image-mode:not(.slideshow-running).collection-mode .buttons .button.collections { opacity: 0.2; } .single-image-mode:not(.slideshow-running).crop-mode .buttons:hover .button.crop, .single-image-mode:not(.slideshow-running).collection-mode .buttons:hover .button.collections { opacity: 1; } .buttons .button.ui-settings { opacity: 0.5; } .buttons .button.ui-settings:hover { opacity: 1; } .buttons .button.touch-controls:after { display: inline-block; content: ""; width: 0.7em; height: 0.6em; border: solid 0.05em silver; border-left: solid 0.2em silver; border-right: solid 0.2em silver; border-radius: 1px; opacity: 0.5; } .buttons .button.touch-controls:hover:after { border: solid 0.05em white; border-left: solid 0.2em white; border-right: solid 0.2em white; opacity: 1; } /* main buttons... */ .main-buttons.buttons { top: 0px; left: 0px; } /* secondary buttons... */ .secondary-buttons.buttons { top: 0px; float: right; } /* .secondary-buttons.buttons { top: 40px; left: 0px; } .secondary-buttons.buttons .button { display: block; } */ /* app buttons... */ .app-buttons.buttons { float: right; margin-left: 40px; z-index: 9999; } .app-buttons .button.close:hover { background: rgba(255, 0, 0, 0.8); } .blur .app-buttons.buttons { -webkit-filter: none !important; filter: none !important; } /* side buttons... */ .side-buttons-left, .side-buttons-right { position: absolute; float: auto; width: 80px; height: 100%; opacity: 0.4; font-size: larger; background: rgba(0, 0, 0, 0.5); width: 120px; z-index: 900; } .side-buttons-left:hover, .side-buttons-right:hover { opacity: 0.4; } .side-buttons-left { left: 0px; } .side-buttons-right { right: 0px; } .side-buttons-left .button, .side-buttons-right .button { display: flex; justify-content: center; align-content: center; flex-direction: row; padding: 10px; line-height: 10px; width: 100%; height: 33.3%; } .side-buttons-left .button { justify-content: flex-end; align-content: flex-start; } .side-buttons-right .button { justify-content: flex-start; align-content: flex-start; } .side-buttons-left .button:first-child { flex-direction: column; justify-content: flex-end; align-items: flex-end; } .side-buttons-right .button:first-child { flex-direction: column; justify-content: flex-end; align-items: flex-start; } .side-buttons-left .button:nth-child(1), .side-buttons-left .button:nth-child(2), .side-buttons-right .button:nth-child(1), .side-buttons-right .button:nth-child(2) { height: 16.65%; } .side-buttons-left .button, .side-buttons-right .button { border-bottom: solid 1px rgba(255, 255, 255, 0.3); } .side-buttons-left .button:last-child, .side-buttons-right .button:last-child { border-bottom: none; } .light .side-buttons-left, .light .side-buttons-right { opacity: 0.3; background: rgba(0, 0, 0, 0.3); } .light .side-buttons-left .button, .light .side-buttons-right .button { color: white; } .single-image-mode .side-buttons-left, .single-image-mode .side-buttons-right { opacity: 0.1; } .single-image-mode.light .side-buttons-left, .single-image-mode.light .side-buttons-right { opacity: 0.05; } /* XXX not sure if this is the right way to go... */ .single-image-mode .main-buttons:not(:hover) .button, .single-image-mode .app-buttons:not(:hover) .button { opacity: 0.1; } .slideshow-running .main-buttons:not(:hover) .button, .slideshow-running .app-buttons:not(:hover) .button { opacity: 0; } /********************************************************** Viewer ***/ .viewer { position: relative; width: 100vw; height: 100vh; overflow: hidden; /*border: solid blue 1px;*/ box-sizing: border-box; user-select: none; } /* XXX this is a stub for printing help/docs... */ @media print { .viewer { display: none; } } /****************************************** Ribbon set and locator ***/ .ribbon-set { position: absolute; display: block; top: 50%; left: 50%; /* NOTE: this needs for scaling/zooming to behave correctly and not shift the element, when its dimensions change... ...this is because .ribbon-set will both be used for scaling and aligning... */ transform-origin: top left; will-change: transform; } .ribbon-locator { position: relative; top: 0; left: 0; will-change: transform; } /********************************************************** Ribbon ***/ /* XXX for some reason setting image size in vmin stops this from stretching in width... */ .shadow, .ribbon { position: relative; display: block; /* XXX BUG: setting this will mess up new ribbon creation.... display: inline-block;*/ height: auto; /*min-width: 0px;*/ width: auto; overflow: visible; white-space: nowrap; font-size: 0; float: left; clear: both; background: var(--ribbon-background-color); margin-top: var(--ribbon-margin); margin-bottom: var(--ribbon-margin); will-change: transform; } .ribbon:empty { display: none; } /* XXX would be good to make this sticky -- always visible... */ .ribbon[title]:before { display: block; position: absolute; content: attr(title); font-size: 52pt; font-style: italic; font-weight: bold; color: white; text-shadow: black 2px 2px 15px; top: -2pt; right: 100%; margin-right: 20pt; } .single-image-mode .ribbon[title]:before { display: none; } .base-ribbon-marker { position: absolute; height: 100%; color: transparent; font-size: 20pt; font-weight: bold; } .base-ribbon-marker:after { content: "base ribbon"; display: block; position: absolute; width: var(--image-tile-size); bottom: 0px; left: 0px; padding: 5px; box-sizing: border-box; z-index: 1000; color: white; background: black; opacity: 0.2; font-size: 20pt; font-weight: bold; transform-origin: bottom left; transform: rotate(-90deg); } .single-image-mode.viewer .base-ribbon-marker { display: none; } /*********************************************************** Image ***/ .marker, .current-marker, .mark, .image { position: relative; display: inline-block; vertical-align: middle; text-align:left; width: var(--image-tile-size); height: var(--image-tile-size); font-size: 12pt; overflow: hidden; box-sizing: border-box; color: white; /* XXX do we need this??? text-shadow: black 0.1em 0.1em 0.4em, black 0.1em 0.1em; */ /* NOTE: we can't set the bg color here because it will get affected by filters... */ background: no-repeat 50% transparent; background-size: contain; border: solid var(--image-border) transparent; /* XXX we are taking care of this in code -- see if we can use this */ image-orientation: none; } .image { padding: var(--single-image-indicator-size); background-color: var(--image-background-color); } .single-image-mode .image { background-color: none; } .image div { display: block; position: absolute; max-width: var(--image-tile-size); width: auto; max-height: var(--image-tile-size); height: auto; left: 50%; top: 50%; transform: translate(-50%,-50%); white-space: normal; text-align: center; text-overflow: ellipsis; /*font-size: 2vh;*/ pointer-events: none; } .crisp-resize .image { image-rendering: -webkit-optimize-contrast; image-rendering: crisp-edges; } /* .current.image { border: solid 5px red; } */ /* NOTE: this is essentially a ribbon... */ .shadow { position: absolute; overflow: visible; width: auto; height: auto; margin: 0px; background: black; -webkit-transition: all 0.1s ease-in; -moz-transition: all 0.1s ease-in; -ms-transition: all 0.1s ease-in; -o-transition: all 0.1s ease-in; transition: all 0.1s ease-in; } .shadow { -webkit-transform-origin: 0 0; -moz-transform-origin: 0 0; -ms-transform-origin: 0 0; -o-transform-origin: 0 0; transform-origin: 0 0; } .image.moving { visibility: hidden; } .current-marker { display: none; position: absolute; border: solid 5px red; background: none; z-index: 100; top: 0; left: 0; margin-top: calc(-1 * var(--image-tile-size) / 2); margin-left: calc(-1 * var(--image-tile-size) / 2); /* pass events through... (do we need IE10-?) */ pointer-events: none; } .marker { width: 50px; border: none; background: no-repeat 50% transparent; background-color: transparent; color: white; } .marker:after { display: block; position: absolute; content: "marker"; font-size: 32px; font-weight: bold; text-align: center; overflow: visible; width: 200px; height: 32px; top: 50%; margin-top: -16px; left: 50%; margin-left: -100px; transform-origin: center center; transform: rotate(270deg) scaleY(1) scaleX(1); opacity: 0.5; } .single-image-mode.viewer .marker { display: none; } /* single image mode transitions */ /* XXX still buggy and not too needed... .single-image-mode.viewer .image { position: absolute; top: 0px; left: 0px; opacity: 0; .transition(opacity); } .single-image-mode.viewer .current.image { opacity: 1; } */ /* image turning... */ /* NOTE: need to account for proportions after turning... */ .image[orientation="90"] { transform: rotate(90deg) scaleY(1) scaleX(1); } .image[orientation="180"] { transform: rotate(180deg) scaleY(1) scaleX(1); } .image[orientation="270"] { transform: rotate(270deg) scaleY(1) scaleX(1); } /* Flipped vertically only... */ /* NOTE: wee need to do all possible combinations here as we can't combine different parts of a transform attr from different classes */ .image[flipped*="vertical"] { transform: rotate(0deg) scaleY(1) scaleX(-1); } .image[orientation="90"][flipped="vertical"] { transform: rotate(90deg) scaleY(1) scaleX(-1) } .image[orientation="180"][flipped="vertical"] { transform: rotate(180deg) scaleY(1) scaleX(-1) } .image[orientation="270"][flipped="vertical"] { transform: rotate(270deg) scaleY(1) scaleX(-1) } /* Flipped horizontally only... */ .image[flipped*="horizontal"] { transform: rotate(0deg) scaleY(-1) scaleX(1); } .image[orientation="90"][flipped="horizontal"] { .transform(90deg, -1) } .image[orientation="180"][flipped="horizontal"] { .transform(180deg, -1) } .image[orientation="270"][flipped="horizontal"] { .transform(270deg, -1) } /* Flipped vertically and horizontally... */ .image[flipped*="vertical"][flipped*="horizontal"] { transform: rotate(0deg) scaleY(-1) scaleX(-1) } .image[orientation="90"][flipped*="vertical"][flipped*="horizontal"] { transform: rotate(90deg) scaleY(-1) scaleX(-1) } .image[orientation="180"][flipped*="vertical"][flipped*="horizontal"] { transform: rotate(180deg) scaleY(-1) scaleX(-1) } .image[orientation="270"][flipped*="vertical"][flipped*="horizontal"] { transform: rotate(270deg) scaleY(-1) scaleX(-1) } /* image separators... */ .ribbon-image-separators.viewer .image { box-shadow: 9px 4px 0 -8px rgba(128,128,128,0.2), -9px 4px 0 -8px rgba(128,128,128,0.2); } .ribbon-image-separators.viewer .image[orientation="90"], .ribbon-image-separators.viewer .image[orientation="270"] { box-shadow: 4px 9px 0 -8px rgba(128,128,128,0.2), 4px -9px 0 -8px rgba(128,128,128,0.2); } .ribbon-image-separators.single-image-mode.viewer .image { box-shadow: none; } /* default backgrounds */ /* XXX not sure if we need these... .image { background-image: url(images/loading.gif); } .image[orientation="90"] { background-image: url(images/loading-90deg.gif); } .image[orientation="180"] { background-image: url(images/loading-180deg.gif); } .image[orientation="270"] { background-image: url(images/loading-270deg.gif); } */ /* separator test */ /* .image.red+.image:not(.red):before { display: inline-block; position: relative; content: ""; top:0px; left: -50px; width: 100px; height: 100%; background-color: yellow; } */ /***************************************************** Image marks ***/ /* .marks-visible.single-image-mode.viewer .marker { display: inline-block; opacity: 0.5; } */ /* .marks-visible.viewer .marked.image:after { display: block; position: absolute; content: ""; font-size: 0pt; border: none; width: @ribbon-mark-size; height: @ribbon-mark-size; top: auto; bottom: @ribbon-mark-offset; left: auto; right: @ribbon-mark-offset; border-radius: 50%; background: blue; box-shadow: 0px 0px 7px 0px black; } .marks-visible.viewer .marked.image[orientation="270"][flipped*="vertical"][flipped*="horizontal"]:after, .marks-visible.viewer .marked.image:not([orientation])[flipped*="vertical"]:after, .marks-visible.viewer .marked.image[orientation="0"][flipped*="vertical"]:after, .marks-visible.viewer .marked.image[orientation="180"][flipped="horizontal"]:after, .marks-visible.viewer .marked.image[orientation="90"]:not([flipped]):after { top: @ribbon-mark-offset; bottom: auto; left: auto; right: @ribbon-mark-offset; } .marks-visible.viewer .marked.image:not([orientation])[flipped*="vertical"][flipped*="horizontal"]:after, .marks-visible.viewer .marked.image[orientation="0"][flipped*="vertical"][flipped*="horizontal"]:after, .marks-visible.viewer .marked.image[orientation="270"][flipped="vertical"]:after, .marks-visible.viewer .marked.image[orientation="90"][flipped="horizontal"]:after, .marks-visible.viewer .marked.image[orientation="180"]:not([flipped]):after { top: @ribbon-mark-offset; bottom: auto; left: @ribbon-mark-offset; right: auto; } .marks-visible.viewer .marked.image[orientation="90"][flipped*="vertical"][flipped*="horizontal"]:after, .marks-visible.viewer .marked.image[orientation="180"][flipped="vertical"]:after, .marks-visible.viewer .marked.image:not([orientation])[flipped*="horizontal"]:after, .marks-visible.viewer .marked.image[orientation="0"][flipped*="horizontal"]:after, .marks-visible.viewer .marked.image[orientation="270"]:not([flipped]):after { top: auto; bottom: @ribbon-mark-offset; left: @ribbon-mark-offset; right: auto; } */ /* NOTE: we use a different mark representation for single image mode... */ /* .marks-visible.single-image-mode.viewer .marked.image:after { display: none; } */ /* corner mark... (a-la bookmarks in PortableMag) * XXX account for flipping... */ /* @ribbon-mark-offset: -15px; .marks-visible.viewer .marked.image:after { display: block; position: absolute; content: ""; font-size: 0pt; border: none; width: 30px; height: 30px; top: @ribbon-mark-offset; right: @ribbon-mark-offset; background: blue; transform: rotate(45deg) scaleY(1) scaleX(1) } .marks-visible.viewer .marked.image[orientation="90"]:after { top: @ribbon-mark-offset; left: @ribbon-mark-offset; } .marks-visible.viewer .marked.image[orientation="180"]:after { bottom: @ribbon-mark-offset; left: @ribbon-mark-offset; } .marks-visible.viewer .marked.image[orientation="270"]:after { bottom: @ribbon-mark-offset; right: @ribbon-mark-offset; } .marked-only-view.viewer:not(.marks-visible) .image:not(.marked) { opacity: 0.3; } */ /* new gen marks... */ .mark { /* this fully covers the image to simplify positioning of actual marks */ margin-left: calc(-1 * var(--image-tile-size)); border: none; } .viewer:not(.marks-visible) .mark { display: none; } .mark.bookmark, .mark.marked { width: 0px; margin-left: 0px; border: none; overflow: visible; } .mark.bookmark:after, .mark.marked:before, .mark.marked:after { display: block; position: absolute; content: ""; font-size: 0pt; border: none; width: var(--image-mark-size); height: var(--image-mark-size); top: auto; bottom: calc(var(--image-tile-size)/30); left: auto; right: calc(var(--image-tile-size)/30); box-shadow: calc(var(--image-tile-size)/300) calc(var(--image-tile-size)/300) calc(var(--image-tile-size)/43) calc(-1 * var(--image-tile-size)/231) rgba(0,0,0,0.8); box-sizing: border-box; border-radius: 50%; background: blue; left: calc(-1 * var(--image-tile-size)/12); } .marks-visible.single-image-mode.viewer .mark:before, .marks-visible.single-image-mode.viewer .mark:after { display: none; } .mark.bookmark:after { background: yellow; left: calc(-1 * var(--image-tile-size)/20); } /* the marked tick... */ .mark.marked:before, .mark.marked:after { top: calc(var(--image-tile-size)/30); left: calc(-1 * var(--image-tile-size)/15); bottom: auto; border-radius: calc(var(--image-tile-size)/100); transform: rotate(-45deg) scaleY(1) scaleX(1); } .mark.marked:before { width: calc(var(--image-tile-size)/100); height: calc(var(--image-tile-size)/50); } .mark.marked:after { width: calc(var(--image-tile-size)/25); height: calc(var(--image-tile-size)/100); } /* XXX these are still experimental... */ .mark.brace-open, .mark.brace-close { width: calc(var(--image-border) * 2); height: var(--image-tile-size); overflow: visible; margin-left: 0px; } .mark.brace-close:after, .mark.brace-open:after { display: block; position: absolute; content: ""; width: calc(var(--image-tile-size) / 20); height: 100%; box-sizing: content-box; border-top: solid calc(var(--image-border)*2) yellow; border-bottom: solid calc(var(--image-border)*2) yellow; margin-top: calc(-1 * var(--image-border) * 2); } .mark.brace-open:after { border-left: solid calc(var(--image-border)*2) yellow; } .mark.brace-close:after { left: calc(-1 * var(--image-tile-size) / 20); border-right: solid calc(var(--image-border)*2) yellow; } .mark.partition { width: var(--image-border); height: var(--image-tile-size); overflow: visible; margin-left: 0px; } .mark.partition:before { display: block; position: absolute; content: ""; width: var(--image-border); height: 102%; background: yellow; margin-top: calc(-1 * var(--image-tile-size) / 50); margin-bottom: 0px; } .mark.partition:after { display: block; position: absolute; left: calc(var(--image-border) * 2); content: attr(text); color: yellow; margin-top: calc(-1 * var(--image-tile-size) / 24); } /****************************************************** Image info ***/ .inline-image-info { display: none; position: absolute; bottom: 0px; width: 100%; background: black; opacity: 0.7; overflow: hidden; white-space: nowrap; } .inline-image-info:hover { user-select: auto; } .inline-image-info::selection { color: white; background: red; } .image-info-visible.viewer .global-image-info, .image-info-visible.viewer .current-marker:hover .inline-image-info, .image-info-visible.viewer .image:hover .inline-image-info { display: block; } .single-image-mode.viewer .current-marker:hover .inline-image-info, .single-image-mode.viewer .image:hover .inline-image-info { display: none; } .image[orientation="90"] .inline-image-info { top: auto; left: 100%; transform-origin: bottom left; transform: rotate(-90deg) scaleY(1) scaleX(1); } .image[orientation="180"] .inline-image-info { top: 0px; bottom: auto; transform: rotate(180deg) scaleY(1) scaleX(1); } .image[orientation="270"] .inline-image-info { top: auto; left: auto; right: 100%; transform-origin: bottom right; transform: rotate(90deg) scaleY(1) scaleX(1); } /* compensate for flipping... */ /* XXX START: I hate this code, will think if a better way to do this... */ .image:not([orientation="90"])[flipped*="horizontal"] .inline-image-info { transform: rotate(0deg) scaleY(-1) scaleX(1); } .image[orientation="90"][flipped*="horizontal"] .inline-image-info { top: auto; bottom: 100%; left: -100%; right: auto; transform-origin: bottom right; transform: rotate(90deg) scaleY(-1) scaleX(1); } .image[orientation="180"][flipped*="horizontal"] .inline-image-info { top: auto; bottom: 100%; left: 0px; right: auto; transform-origin: bottom right; transform: rotate(180deg) scaleY(-1) scaleX(1); } .image[orientation="270"][flipped*="horizontal"] .inline-image-info { top: auto; bottom: 0px; left: 0px; right: auto; transform-origin: bottom right; transform: rotate(270deg) scaleY(-1) scaleX(1); } .image[flipped*="vertical"] .inline-image-info { top: 0px; bottom: auto; transform: rotate(0deg) scaleY(1) scaleX(-1); } .image[orientation="90"][flipped*="vertical"] .inline-image-info { top: auto; bottom: 100%; left: 100%; right: auto; transform-origin: bottom left; transform: rotate(-270deg) scaleY(1) scaleX(-1); } .image[orientation="180"][flipped*="vertical"] .inline-image-info { top: auto; bottom: 0px; left: -100%; right: auto; transform-origin: bottom right; transform: rotate(180deg) scaleY(1) scaleX(-1); } .image[orientation="270"][flipped*="vertical"] .inline-image-info { top: auto; bottom: 100%; left: -100%; right: auto; transform-origin: bottom right; transform: rotate(270deg) scaleY(1) scaleX(-1); } .image[flipped*="vertical"][flipped*="horizontal"] .inline-image-info { top: 0px; bottom: auto; transform: rotate(0deg) scaleY(-1) scaleX(-1); } .image[orientation="90"][flipped*="vertical"][flipped*="horizontal"] .inline-image-info { top: auto; bottom: 0px; left: -100%; right: auto; transform-origin: bottom right; transform: rotate(-90deg) scaleY(-1) scaleX(-1); } .image[orientation="180"][flipped*="vertical"][flipped*="horizontal"] .inline-image-info { top: auto; bottom: 0px; left: auto; right: auto; transform-origin: bottom right; transform: rotate(180deg) scaleY(-1) scaleX(-1); } .image[orientation="270"][flipped*="vertical"][flipped*="horizontal"] .inline-image-info { top: auto; bottom: 100%; left: auto; right: auto; transform-origin: bottom right; transform: rotate(90deg) scaleY(-1) scaleX(-1); } /* XXX END */ .overlay-info { display: none; position: absolute; bottom: 0px; left: 0px; width: 100%; padding: 2px; padding-left: 10px; padding-right: 10px; box-sizing: border-box; background: rgba(0, 0, 0, 0.6); color: silver; text-shadow: -1px -1px 1px rgba(255, 255, 255, 0.2), 1px 1px 2px rgba(0, 0, 0, 0.3); opacity: 0.9; } .overlay-info>* { float: left; } .overlay-info:hover { user-select: auto; } .overlay-info .spacer { opacity: 0.5, } .overlay-info .spacer~* { float: right; } .overlay-info .secondary { font-style: italic; font-size: small; color: silver; } .overlay-info::selection, .overlay-info ::selection { color: white; background: red; } .overlay-info.hidden, .overlay-info.full, .overlay-info.minimal { display: block; /* XXX is this correct??? */ z-index: 1000, } .overlay-info.hidden { background: transparent; } .overlay-info.hidden>* { opacity: 0 !important; } .overlay-info.minimal { background: transparent; /* //background: -moz-linear-gradient(top, rgba(0,0,0,0) 0%, rgba(0,0,0,0.3) 100%); //background: -webkit-linear-gradient(top, rgba(0,0,0,0) 0%, rgba(0,0,0,0.3) 100%); //background: linear-gradient(to bottom, rgba(0,0,0,0) 0%, rgba(0,0,0,0.3) 100%); //filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00000000', endColorstr='#b5000000',GradientType=0 ); */ } .overlay-info.minimal .full-only { display: none; } /* space elements... */ .overlay-info>:not(:first-child) { margin-left: 10px; } .overlay-info .info { font-style: italic; } .overlay-info .gid:before, .overlay-info .gid:after { opacity: 0.8; } .overlay-info .gid:before { content: "("; } .overlay-info .gid:after { content: ")"; } /* XXX REUSE: this is the same as marked/bookmarked image markers... */ .overlay-info .marked, .overlay-info .marked:after, .overlay-info .marked:before, .overlay-info .bookmarked:after { display: block; position: relative; content: ""; font-size: 0pt; border: none; margin-top: 4px; margin-bottom: 4px; /*margin-right: 10px;*/ width: 10px; height: 10px; /*box-shadow: 1px 1px 10px -2px rgba(0,0,0,0.7);*/ box-sizing: border-box; border-radius: 50%; background: blue; cursor: pointer; } /* tick... */ .overlay-info .marked { background: transparent; } .overlay-info .marked:before, .overlay-info .marked:after { position: absolute; bottom: auto; border-radius: 3px; transform: rotate(-45deg) scaleY(1) scaleX(1); } .overlay-info .marked:before { width: 3px; height: 6px; } .overlay-info .marked:after { width: 12px; height: 3px; } .overlay-info .bookmarked:after { background: yellow; } .overlay-info .marked:not(.on), .overlay-info .bookmarked:not(.on) { opacity: 0.5; } .overlay-info .marked:not(.on):before, .overlay-info .marked:not(.on):after, .overlay-info .bookmarked:not(.on):after { background: gray; } /* image index status element */ .overlay-info .index { cursor: pointer; } .overlay-info .index .position.editable { cursor: text; } .overlay-info .index.loaded:after, .overlay-info .index.global:after { content: "G"; opacity: 0.7; font-size: small; } .overlay-info .index.loaded:after { content: "L"; } /* .overlay-info .index.global:hover:after { content: "Global"; } */ /* ribbon */ .overlay-info .ribbon-number { opacity: 0.7; } .overlay-info .ribbon-number:before { content: "R:"; opacity: 0.7; } /* XXX not sure if we need to expand this .overlay-info .ribbon-number:hover:before { content: "Ribbon: "; opacity: 0.6; } */ .overlay-info .ribbon-index[base] { /* NOTE: we are using shadow instead of a border or underline here as we need to control both the uniform shading and placement without overcomplicating things when having to compensate for alignment... */ /*border-bottom: solid 2px yellow;*/ box-shadow: 0 -2px 0 0 yellow inset; } .overlay-info .ribbon-count { opacity: 0.7; /*font-size: small;*/ } .overlay-info .ribbon-count:not(:empty):before { content: "/"; } /* changes */ .overlay-info .changes { cursor: default; } /* gid */ .overlay-info .gid { opacity: 0.7; } .overlay-info .gid:hover { opacity: 1; } .overlay-info .path { opacity: 0.7; } .overlay-info .path:hover { opacity: 1; } /* Capslock indicator.. */ .overlay-info .capslock-state { font-size: small; font-style: italic; margin: 0px 10pt; cursor: default; } .overlay-info .capslock-state:not(.on) { opacity: 0.2; } .overlay-info .capslock-state.on { color: yellow; opacity: 0.6; } .overlay-info .capslock-state:hover { opacity: 0.8; } /*************************************************** Global status ***/ .global-status { display: block; opacity: 1; z-index: 1000; } /****************************************************** Indicators ***/ .up-indicator, .down-indicator, .start-indicator, .end-indicator, .top-indicator, .bottom-indicator { display: block; position: absolute; content: ""; top: 0px; left: 50%; height: 50px; width: 100px; margin-left: -50px; overflow: hidden; cursor: pointer; z-index: 9999; } .up-indicator:after, .down-indicator:after { display: inline-block; position: absolute; content: ""; width: 50px; height: 50px; bottom: -25px; left: 25px; background: yellow; transform: rotate(45deg) scaleY(1) scaleX(1); } .down-indicator { top: auto; bottom: 0px; } .down-indicator:after { top: -25px; bottom: auto; } .start-indicator, .end-indicator { left: 0px; width: 10px; height: 100%; margin: 0px; background: yellow; } .end-indicator { left: auto; right: 0px; } .top-indicator, .bottom-indicator { left: 0px; height: 10px; width: 100%; margin: 0px; background: yellow; } .bottom-indicator { top: auto; bottom: 0px; } /* default state */ .up-indicator, .down-indicator, .start-indicator, .end-indicator, .top-indicator, .bottom-indicator { display: none; } /* these are generic containers for indicators */ .global-mode-indicators, .context-mode-indicators { position: absolute; height: 20px; width: auto; min-width: var(--image-tile-size); text-align: right; color: transparent; } .global-mode-indicators { top: 20px; right: 20px; } .context-mode-indicators { right: 20px; bottom: 20px; } .global-mode-indicators .mode-tip, .context-mode-indicators .mode-tip { display: none; opacity: 0.5; font-weight: bold; color: gray; } .global-mode-indicators:hover .mode-tip, .context-mode-indicators:hover .mode-tip { display: inline-block; } .global-mode-indicators > *, .context-mode-indicators > * { font-size: small; vertical-align: middle; margin-left: 10px; } .global-mode-indicators .circle, .context-mode-indicators .circle { display: inline-block; width: var(--single-image-indicator-size); height: var(--single-image-indicator-size); border-radius: 50%; } /* hide indicators in single image mode */ .single-image-mode.viewer .global-mode-indicators { opacity: 0.5; } .light.single-image-mode.viewer .global-mode-indicators { opacity: 0.1; } .dark.single-image-mode.viewer .global-mode-indicators { opacity: 0.6; } .single-image-mode.viewer .global-mode-indicators:hover { opacity: 1; } .global-mode-indicators .indicator, .context-mode-indicators .indicator { display: none; height: 20px; vertical-align: middle; } /* actual indicators */ /* marks... */ .global-mode-indicators .marked-only-visible, .global-mode-indicators .marks-visible, .context-mode-indicators .current-image-marked { color: blue; cursor: pointer; text-shadow: rgba(0,0,0,0.5) 0.1em 0.1em 0.4em, rgba(0,0,0,0.5) 0.1em 0.1em; } .context-mode-indicators .current-image-bookmarked { color: yellow; cursor: pointer; text-shadow: rgba(0,0,0,0.5) 0.1em 0.1em 0.4em, rgba(0,0,0,0.5) 0.1em 0.1em; } .global-mode-indicators .marked-only-visible .shown, .global-mode-indicators .marks-visible .shown, .context-mode-indicators .current-image-bookmarked .shown, .context-mode-indicators .current-image-marked .shown { display: none; } .global-mode-indicators .marked-only-visible:after, .global-mode-indicators .marks-visible:after, .context-mode-indicators .current-image-bookmarked:after, .context-mode-indicators .current-image-marked:after { display: inline-block; width: 6px; height: 6px; border-radius: 50%; content: ""; background-color: blue; border: solid 2px blue; margin-left: 5px; margin-top: 3px; top: 50%; box-shadow: 1px 1px 10px -2px rgba(0,0,0,0.7); } .global-mode-indicators .marked-only-visible:after, .global-mode-indicators .marks-visible:after, .context-mode-indicators .current-image-marked:after { color: blue; } .context-mode-indicators .current-image-bookmarked:after { color: yellow; background-color: yellow; border: solid 2px yellow; } .marks-visible.viewer .global-mode-indicators .marks-visible { display: inline-block; } /* image mark in single image mode... */ .single-image-mode.marks-visible.viewer .context-mode-indicators .current-image-bookmarked, .single-image-mode.marks-visible.viewer .context-mode-indicators .current-image-marked { /*display: none;*/ display: inline-block; text-decoration: line-through; opacity: 0.3; } .single-image-mode.marks-visible.viewer .context-mode-indicators .current-image-bookmarked.shown, .single-image-mode.marks-visible.viewer .context-mode-indicators .current-image-marked.shown { display: inline-block; text-decoration: none; opacity: 1; } .single-image-mode.marks-visible.viewer .context-mode-indicators .current-image-bookmarked:not(.shown):after, .single-image-mode.marks-visible.viewer .context-mode-indicators .current-image-marked:not(.shown):after { background-color: transparent; } .single-image-mode.marks-visible.viewer .context-mode-indicators .current-image-bookmarked:not(.shown):hover, .single-image-mode.marks-visible.viewer .context-mode-indicators .current-image-marked:not(.shown):hover { opacity: 0.8; } .cropped-view.marks-visible.viewer .global-mode-indicators .cropped-view { color: gray; display: inline-block; } .ribbon-indicator { display: none; position: absolute; top: 10px; left: 15px; color: white; font-size: 42px; font-weight: bold; font-style: italic; text-shadow: black 0.1em 0.1em 0.6em; opacity: 0.1; } .flashing-ribbon-indicator { display: inline-block; } .single-image-mode.marks-visible.viewer .ribbon-indicator { display: inline-block; } .ribbon-indicator:hover:after { display: inline-block; content: "ribbon number"; font-size: 14px; opacity: 0.8; } .show-passive-base-ribbon-indicator:not(.single-image-mode) .base.ribbon:after { content: ""; position: absolute; display: block; width: 100%; height: calc(var(--image-tile-size)/50); top: 101%; /*left: -100%;*/ background: yellow; opacity: 0.8; } .range-offscreen-indicator { display: none; position: fixed; width: calc(var(--image-tile-size) / 16); height: calc(var(--image-tile-size) / 4); margin-top: calc(-1 * var(--image-tile-size) / 8); box-sizing: border-box; border-top: solid calc(var(--image-tile-size) / 8) transparent; border-bottom: solid calc(var(--image-tile-size) / 8) transparent; } .range-offscreen-indicator.left { border-right: solid calc(var(--image-tile-size) / 16) yellow; border-left: solid calc(var(--image-border) * 2) transparent; } .range-offscreen-indicator.right { border-left: solid calc(var(--image-tile-size) / 16) yellow; border-right: solid calc(var(--image-border) * 2) transparent; } /*************************************************** Progress bars ***/ progress { -webkit-appearance: none; -moz-appearance: none; appearance: none; height: 2px; } progress::-webkit-progress-bar { background: rgba(0,0,0,0.5); } progress::-webkit-progress-value { background: yellow; } /* progress:not(value)::-webkit-progress-bar { background: transparent; background-image: -webkit-linear-gradient(-45deg, transparent 33%, rgba(0,0,0,0.2) 33%, rgba(0,0,0,0.2) 66%, transparent 66%), -webkit-linear-gradient(left, yellow, orange, yellow); background-size: 50px 50px; -webkit-animation: animate-progress 5s linear infinite; animation: animate-progress 5s linear infinite; } @-webkit-keyframes animate-progress { 100% { background-position: -100% 0px; } } @keyframes animate-progress { 100% { background-position: -100% 0px; } } */ .progress-container { position: absolute; top: 30px; margin: 5px; padding: 2px; background: rgba(0,0,0,0.1); z-index: 4000; } .progress-container:hover { background: rgba(0,0,0,0.2); } .progress-container:empty { display: none; } .progress-bar { position: relative; color: silver; font-size: 10px; margin: 10px; } .progress-bar .close { display: none; position: absolute; top: -10px; right: 0px; width: 20px; font-size: 20px; text-align: center; opacity: 0.3; cursor: pointer; } .progress-bar:hover .close { display: inline-block; } .progress-bar .close:hover { opacity: 1; color: red; } .progress-bar progress { display: block; width: 100%; min-width: 300px; } /********************************************** Mode: single image ***/ .single-image-mode.viewer .ribbon { background-color: transparent; will-change: auto; } .single-image-mode.viewer .current-marker { /* NOTE: !important here fixes the jQuery habit of explicitly setting display on .show(..)/.hide(..)/.fadeIn(..)/... ...if this proves to be a problem, use visibility instead of !important... */ display: none !important; } .single-image-mode.viewer .image { background-color: transparent; /* NOTE: need to keep a distance from screen borders... */ border: solid transparent 2px; } .single-image-mode.viewer .image:not(.current) { /* XXX for some reason this breaks the alignment on large magnifications... display: none; */ /* XXX this makes images pass through the :visible filter... opacity: 0; */ visibility: hidden; } /************************************ Ribbon Themes (experimental) ***/ /* XXX should these be merged with general themes?? */ .viewer:not(.single-image-mode).black-ribbon .ribbon { } .viewer:not(.single-image-mode).gray-ribbon .ribbon { background-color: rgba(0, 0, 0, 0.6); } .viewer:not(.single-image-mode).light-gray-ribbon .ribbon { background-color: rgba(0, 0, 0, 0.2); } .viewer:not(.single-image-mode).transparent-ribbon .ribbon { background-color: transparent; } /********************************************************** Themes ***/ /* XXX this is by no means final... */ /*@import "theme-light";*/ .light.viewer .metadata-view .preview.image, .light.single-image-mode.viewer .image, .light.transparent-ribbon.viewer .image { color: black; } .light.viewer, .light.viewer .overlay-block .background { background: white; } .light.viewer .overlay-block .dialog { } .light.viewer .overlay-block:hover .background:after { color: black; } .light.viewer .ribbon-set:empty:before, .light.viewer .ribbon-set:empty:after { color: gray; } .light.viewer .ribbon-indicator { color: silver; text-shadow: none; opacity: 0.3; } .light.viewer .ribbon-indicator:hover:after { color: gray; text-shadow: none; opacity: 0.8; } .light.viewer progress::-webkit-progress-bar { background: rgba(0,0,0,0.1); } .light.viewer progress::-webkit-progress-value { background: red; } .light.viewer .progress-container { background: rgba(0, 0, 0, 0.03); } .light.viewer .progress-container:hover { background: rgba(0, 0, 0, 0.05); } .light.viewer .progress-bar { color: rgba(0,0,0,0.6); } /*@import "theme-gray";*/ .gray.viewer, .gray.viewer .overlay-block .background { background: var(--background-color); } .gray.viewer .overlay-block .dialog { background: var(--dialog-background-color); } .gray.viewer .overlay-block:hover .background:after { color: silver; opacity: 0.4; } /*@import "theme-dark";*/ .dark.viewer, .dark.viewer .overlay-block .background { background: var(--background-color); } .dark.viewer .overlay-block .dialog { background: var(--dialog-background-color); } .dark.viewer .overlay-block:hover .background:after { color: gray; opacity: 0.4; } .dark.viewer .ribbon-indicator { opacity: 0.2; } .dark.viewer .ribbon-indicator:hover:after { opacity: 0.8; } .dark.viewer progress::-webkit-progress-bar { background: rgba(255,255,255,0.2); } .dark.viewer .progress-container { border: solid 1px transparent; } .dark.viewer .progress-container:hover { border: solid 1px rgba(255, 255,255, 0.1); } .dark.viewer .progress-container:hover progress::-webkit-progress-bar { background: rgba(255,255,255,0.3); } .large.viewer:not(.single-image-mode) .current-marker { border-width: 2px; } .large.viewer:not(.single-image-mode) .mark:after, .large.viewer:not(.single-image-mode) .marked.image:after { transform: rotate(0deg) scaleY(0.7) scaleX(0.7); } .small.viewer:not(.single-image-mode) .mark:after, .small.viewer:not(.single-image-mode) .marked.image:after { transform: rotate(0deg) scaleY(1.5) scaleX(1.5); } /********************************************************* Overlay ***/ .overlay-block { display: none; position: absolute; top: 0px; left: 0px; height: 100%; width: 100%; } .viewer.overlay .overlay-block { display: block; } /* XXX this is experimental... */ .viewer.overlay .ribbon-set { /* XXX blur makes things slow with transparency... */ -webkit-filter: /*blur(2px)*/ grayscale(.5); filter: /*blur(2px)*/ grayscale(.5); /* -webkit-animation-name: testAnim; -webkit-animation-duration: .2s; -webkit-animation-iteration-count: 1; -webkit-animation-direction: alternate; -webkit-animation-timing-function: ease-out; -webkit-animation-fill-mode: forwards; -webkit-animation-delay: 0s; */ } .overlay-block .content, .overlay-block .background { /* XXX for some magical reason position and top are overwritten with 'static' and 'auto' values respectively */ position: absolute !important; top: 0px !important; left: 0px; height: 100%; width: 100%; cursor: auto; opacity: 0.9; } .overlay-block .content, .overlay-block .content table { background: transparent; } .overlay-block .background { opacity: 0.7; } .overlay-block:hover .background:after { display: inline-block; position: absolute; content: 'Click background to close.'; height: auto; width: auto; bottom: 20px; right: 20px; color: white; opacity: 0.7; } .overlay-block .dialog { display: inline-block; min-height: 50px; min-width: 300px; /* XXX for some reason this is not sized correctly... */ max-height: 90%; max-width: 90%; /* XXX this needs to be lower priority than max-height... */ /*overflow-y: auto;*/ color: white; border: solid silver 1px; border-radius: 3px; background: gray; padding: 20px; vertical-align: middle; box-shadow: 0px 5px 50px 0px black; } /* tables in dialogs... */ .overlay-block .dialog table { color: white; font-size: small; user-select: auto; } .overlay-block .dialog table tr td:first-child { text-align: right; font-weight: bold; } .overlay-block .dialog table tr td:last-child { color: silver; } .overlay-block .dialog .choice .item { text-align: left; } .field :focus { box-shadow: 0px 0px 3px 0px red; } /* XXX this is a hack -- hide the radio button itself... */ .field.choice input[type=radio] { opacity: 0; position: absolute; } .field.choice input ~ span { display: block; padding: 1px; padding-left: 5px; padding-right: 5px; } .field.choice :checked ~ span { color: white; background: gray; } .field.choice :focus ~ span { box-shadow: 0px 0px 3px 0px red; } .light.viewer .field.choice :checked ~ span { color: white; background: silver; } .field .disabled-text { opacity: 0.5; } /************************************************************ Help ***/ /* XXX make this more generic, and not just for the keyboard... */ /* this is for sliding stuff */ .viewer.drawer-mode { box-shadow: 0px 0px 50px 0px silver; } /* help */ .keyboard-help { width: 80%; margin-top: 20px; margin-left: 15%; margin-right: 5%; margin-bottom: 100px; } .keyboard-help .section-doc { font-size: small; vertical-align: top; font-style: italic; } .keyboard-help th { text-align: left; height: 50px; vertical-align: bottom; border-bottom: solid gray 1px; } .keyboard-help tr:hover { background: #eee; vertical-align: top; } .keyboard-help tr td:first-child { color: gray; font-style: italic; padding-right: 20px; padding-left: 10px; } .keyboard-help .section-doc td:only-child { padding-right: 0px; padding-left: 0px; } /********************************************************************** * vim:set spell ft=css : */