From 4bbed1dc12e6cd8b7a7fff23b5b7b3e9f7c8eecc Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Sat, 11 Jan 2025 17:51:02 +0100 Subject: [PATCH 01/38] Standardize on 4 space-indentation in CSS files This is what we use in every other file in noVNC. It also much more common for a CSS file in general. By standardizing on 4 spaces we can avoid indentation mistakes. --- app/styles/base.css | 888 +++++++++++++++++++++---------------------- app/styles/input.css | 262 ++++++------- 2 files changed, 575 insertions(+), 575 deletions(-) diff --git a/app/styles/base.css b/app/styles/base.css index 395c18e..06e3d5a 100644 --- a/app/styles/base.css +++ b/app/styles/base.css @@ -30,30 +30,30 @@ */ :root { - font-family: sans-serif; + font-family: sans-serif; } body { - margin:0; - padding:0; - /*Background image with light grey curve.*/ - background-color:#494949; - background-repeat:no-repeat; - background-position:right bottom; - height:100%; - touch-action: none; + margin:0; + padding:0; + /*Background image with light grey curve.*/ + background-color:#494949; + background-repeat:no-repeat; + background-position:right bottom; + height:100%; + touch-action: none; } html { - height:100%; + height:100%; } .noVNC_only_touch.noVNC_hidden { - display: none; + display: none; } .noVNC_disabled { - color: rgb(128, 128, 128); + color: rgb(128, 128, 128); } /* ---------------------------------------- @@ -62,33 +62,33 @@ html { */ .noVNC_spinner { - position: relative; + position: relative; } .noVNC_spinner, .noVNC_spinner::before, .noVNC_spinner::after { - width: 10px; - height: 10px; - border-radius: 2px; - box-shadow: -60px 10px 0 rgba(255, 255, 255, 0); - animation: noVNC_spinner 1.0s linear infinite; + width: 10px; + height: 10px; + border-radius: 2px; + box-shadow: -60px 10px 0 rgba(255, 255, 255, 0); + animation: noVNC_spinner 1.0s linear infinite; } .noVNC_spinner::before { - content: ""; - position: absolute; - left: 0px; - top: 0px; - animation-delay: -0.1s; + content: ""; + position: absolute; + left: 0px; + top: 0px; + animation-delay: -0.1s; } .noVNC_spinner::after { - content: ""; - position: absolute; - top: 0px; - left: 0px; - animation-delay: 0.1s; + content: ""; + position: absolute; + top: 0px; + left: 0px; + animation-delay: 0.1s; } @keyframes noVNC_spinner { - 0% { box-shadow: -60px 10px 0 rgba(255, 255, 255, 0); width: 20px; } - 25% { box-shadow: 20px 10px 0 rgba(255, 255, 255, 1); width: 10px; } - 50% { box-shadow: 60px 10px 0 rgba(255, 255, 255, 0); width: 10px; } + 0% { box-shadow: -60px 10px 0 rgba(255, 255, 255, 0); width: 20px; } + 25% { box-shadow: 20px 10px 0 rgba(255, 255, 255, 1); width: 10px; } + 50% { box-shadow: 60px 10px 0 rgba(255, 255, 255, 0); width: 10px; } } /* ---------------------------------------- @@ -97,39 +97,39 @@ html { */ .noVNC_center { - /* - * This is a workaround because webkit misrenders transforms and - * uses non-integer coordinates, resulting in blurry content. - * Ideally we'd use "top: 50%; transform: translateY(-50%);" on - * the objects instead. - */ - display: flex; - align-items: center; - justify-content: center; - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - pointer-events: none; + /* + * This is a workaround because webkit misrenders transforms and + * uses non-integer coordinates, resulting in blurry content. + * Ideally we'd use "top: 50%; transform: translateY(-50%);" on + * the objects instead. + */ + display: flex; + align-items: center; + justify-content: center; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; } .noVNC_center > * { - pointer-events: auto; + pointer-events: auto; } .noVNC_vcenter { - display: flex !important; - flex-direction: column; - justify-content: center; - position: fixed; - top: 0; - left: 0; - height: 100%; - margin: 0 !important; - padding: 0 !important; - pointer-events: none; + display: flex !important; + flex-direction: column; + justify-content: center; + position: fixed; + top: 0; + left: 0; + height: 100%; + margin: 0 !important; + padding: 0 !important; + pointer-events: none; } .noVNC_vcenter > * { - pointer-events: auto; + pointer-events: auto; } /* ---------------------------------------- @@ -138,7 +138,7 @@ html { */ .noVNC_connect_layer { - z-index: 60; + z-index: 60; } /* ---------------------------------------- @@ -147,69 +147,69 @@ html { */ #noVNC_fallback_error { - z-index: 1000; - visibility: hidden; - /* Put a dark background in front of everything but the error, - and don't let mouse events pass through */ - background: rgba(0, 0, 0, 0.8); - pointer-events: all; + z-index: 1000; + visibility: hidden; + /* Put a dark background in front of everything but the error, + and don't let mouse events pass through */ + background: rgba(0, 0, 0, 0.8); + pointer-events: all; } #noVNC_fallback_error.noVNC_open { - visibility: visible; + visibility: visible; } #noVNC_fallback_error > div { - max-width: calc(100vw - 30px - 30px); - max-height: calc(100vh - 30px - 30px); - overflow: auto; + max-width: calc(100vw - 30px - 30px); + max-height: calc(100vh - 30px - 30px); + overflow: auto; - padding: 15px; + padding: 15px; - transition: 0.5s ease-in-out; + transition: 0.5s ease-in-out; - transform: translateY(-50px); - opacity: 0; + transform: translateY(-50px); + opacity: 0; - text-align: center; - font-weight: bold; - color: #fff; + text-align: center; + font-weight: bold; + color: #fff; - border-radius: 10px; - box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); - background: rgba(200,55,55,0.8); + border-radius: 10px; + box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); + background: rgba(200,55,55,0.8); } #noVNC_fallback_error.noVNC_open > div { - transform: translateY(0); - opacity: 1; + transform: translateY(0); + opacity: 1; } #noVNC_fallback_errormsg { - font-weight: normal; + font-weight: normal; } #noVNC_fallback_errormsg .noVNC_message { - display: inline-block; - text-align: left; - font-family: monospace; - white-space: pre-wrap; + display: inline-block; + text-align: left; + font-family: monospace; + white-space: pre-wrap; } #noVNC_fallback_error .noVNC_location { - font-style: italic; - font-size: 0.8em; - color: rgba(255, 255, 255, 0.8); + font-style: italic; + font-size: 0.8em; + color: rgba(255, 255, 255, 0.8); } #noVNC_fallback_error .noVNC_stack { - padding: 10px; - margin: 10px; - font-size: 0.8em; - text-align: left; - font-family: monospace; - white-space: pre; - border: 1px solid rgba(0, 0, 0, 0.5); - background: rgba(0, 0, 0, 0.2); - overflow: auto; + padding: 10px; + margin: 10px; + font-size: 0.8em; + text-align: left; + font-family: monospace; + white-space: pre; + border: 1px solid rgba(0, 0, 0, 0.5); + background: rgba(0, 0, 0, 0.2); + overflow: auto; } /* ---------------------------------------- @@ -218,325 +218,325 @@ html { */ #noVNC_control_bar_anchor { - /* The anchor is needed to get z-stacking to work */ - position: fixed; - z-index: 10; + /* The anchor is needed to get z-stacking to work */ + position: fixed; + z-index: 10; - transition: 0.5s ease-in-out; + transition: 0.5s ease-in-out; - /* Edge misrenders animations wihthout this */ - transform: translateX(0); + /* Edge misrenders animations wihthout this */ + transform: translateX(0); } :root.noVNC_connected #noVNC_control_bar_anchor.noVNC_idle { - opacity: 0.8; + opacity: 0.8; } #noVNC_control_bar_anchor.noVNC_right { - left: auto; - right: 0; + left: auto; + right: 0; } #noVNC_control_bar { - position: relative; - left: -100%; + position: relative; + left: -100%; - transition: 0.5s ease-in-out; + transition: 0.5s ease-in-out; - background-color: rgb(110, 132, 163); - border-radius: 0 10px 10px 0; + background-color: rgb(110, 132, 163); + border-radius: 0 10px 10px 0; - user-select: none; - -webkit-user-select: none; - -webkit-touch-callout: none; /* Disable iOS image long-press popup */ + user-select: none; + -webkit-user-select: none; + -webkit-touch-callout: none; /* Disable iOS image long-press popup */ } #noVNC_control_bar.noVNC_open { - box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); - left: 0; + box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); + left: 0; } #noVNC_control_bar::before { - /* This extra element is to get a proper shadow */ - content: ""; - position: absolute; - z-index: -1; - height: 100%; - width: 30px; - left: -30px; - transition: box-shadow 0.5s ease-in-out; + /* This extra element is to get a proper shadow */ + content: ""; + position: absolute; + z-index: -1; + height: 100%; + width: 30px; + left: -30px; + transition: box-shadow 0.5s ease-in-out; } #noVNC_control_bar.noVNC_open::before { - box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); + box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); } .noVNC_right #noVNC_control_bar { - left: 100%; - border-radius: 10px 0 0 10px; + left: 100%; + border-radius: 10px 0 0 10px; } .noVNC_right #noVNC_control_bar.noVNC_open { - left: 0; + left: 0; } .noVNC_right #noVNC_control_bar::before { - visibility: hidden; + visibility: hidden; } #noVNC_control_bar_handle { - position: absolute; - left: -15px; - top: 0; - transform: translateY(35px); - width: calc(100% + 30px); - height: 50px; - z-index: -1; - cursor: pointer; - border-radius: 5px; - background-color: rgb(83, 99, 122); - background-image: url("../images/handle_bg.svg"); - background-repeat: no-repeat; - background-position: right; - box-shadow: 3px 3px 0px rgba(0, 0, 0, 0.5); + position: absolute; + left: -15px; + top: 0; + transform: translateY(35px); + width: calc(100% + 30px); + height: 50px; + z-index: -1; + cursor: pointer; + border-radius: 5px; + background-color: rgb(83, 99, 122); + background-image: url("../images/handle_bg.svg"); + background-repeat: no-repeat; + background-position: right; + box-shadow: 3px 3px 0px rgba(0, 0, 0, 0.5); } #noVNC_control_bar_handle:after { - content: ""; - transition: transform 0.5s ease-in-out; - background: url("../images/handle.svg"); - position: absolute; - top: 22px; /* (50px-6px)/2 */ - right: 5px; - width: 5px; - height: 6px; + content: ""; + transition: transform 0.5s ease-in-out; + background: url("../images/handle.svg"); + position: absolute; + top: 22px; /* (50px-6px)/2 */ + right: 5px; + width: 5px; + height: 6px; } #noVNC_control_bar.noVNC_open #noVNC_control_bar_handle:after { - transform: translateX(1px) rotate(180deg); + transform: translateX(1px) rotate(180deg); } :root:not(.noVNC_connected) #noVNC_control_bar_handle { - display: none; + display: none; } .noVNC_right #noVNC_control_bar_handle { - background-position: left; + background-position: left; } .noVNC_right #noVNC_control_bar_handle:after { - left: 5px; - right: 0; - transform: translateX(1px) rotate(180deg); + left: 5px; + right: 0; + transform: translateX(1px) rotate(180deg); } .noVNC_right #noVNC_control_bar.noVNC_open #noVNC_control_bar_handle:after { - transform: none; + transform: none; } /* Larger touch area for the handle, used when a touch screen is available */ #noVNC_control_bar_handle div { - position: absolute; - right: -35px; - top: 0; - width: 50px; - height: 100%; - display: none; + position: absolute; + right: -35px; + top: 0; + width: 50px; + height: 100%; + display: none; } @media (any-pointer: coarse) { - #noVNC_control_bar_handle div { - display: initial; - } + #noVNC_control_bar_handle div { + display: initial; + } } .noVNC_right #noVNC_control_bar_handle div { - left: -35px; - right: auto; + left: -35px; + right: auto; } #noVNC_control_bar > .noVNC_scroll { - max-height: 100vh; /* Chrome is buggy with 100% */ - overflow-x: hidden; - overflow-y: auto; - padding: 0 10px; + max-height: 100vh; /* Chrome is buggy with 100% */ + overflow-x: hidden; + overflow-y: auto; + padding: 0 10px; } #noVNC_control_bar > .noVNC_scroll > * { - display: block; - margin: 10px auto; + display: block; + margin: 10px auto; } /* Control bar hint */ #noVNC_hint_anchor { - position: fixed; - right: -50px; - left: auto; + position: fixed; + right: -50px; + left: auto; } #noVNC_control_bar_anchor.noVNC_right + #noVNC_hint_anchor { - left: -50px; - right: auto; + left: -50px; + right: auto; } #noVNC_control_bar_hint { - position: relative; - transform: scale(0); - width: 100px; - height: 50%; - max-height: 600px; + position: relative; + transform: scale(0); + width: 100px; + height: 50%; + max-height: 600px; - visibility: hidden; - opacity: 0; - transition: 0.2s ease-in-out; - background: transparent; - box-shadow: 0 0 10px black, inset 0 0 10px 10px rgba(110, 132, 163, 0.8); - border-radius: 10px; - transition-delay: 0s; + visibility: hidden; + opacity: 0; + transition: 0.2s ease-in-out; + background: transparent; + box-shadow: 0 0 10px black, inset 0 0 10px 10px rgba(110, 132, 163, 0.8); + border-radius: 10px; + transition-delay: 0s; } #noVNC_control_bar_hint.noVNC_active { - visibility: visible; - opacity: 1; - transition-delay: 0.2s; - transform: scale(1); + visibility: visible; + opacity: 1; + transition-delay: 0.2s; + transform: scale(1); } #noVNC_control_bar_hint.noVNC_notransition { - transition: none !important; + transition: none !important; } /* Control bar buttons */ #noVNC_control_bar .noVNC_button { - padding: 4px 4px; - vertical-align: middle; - border:1px solid rgba(255, 255, 255, 0.2); - border-radius: 6px; - background-color: transparent; - background-image: unset; /* we don't want the gradiant from input.css */ + padding: 4px 4px; + vertical-align: middle; + border:1px solid rgba(255, 255, 255, 0.2); + border-radius: 6px; + background-color: transparent; + background-image: unset; /* we don't want the gradiant from input.css */ } #noVNC_control_bar .noVNC_button.noVNC_selected { - border-color: rgba(0, 0, 0, 0.8); - background-color: rgba(0, 0, 0, 0.5); + border-color: rgba(0, 0, 0, 0.8); + background-color: rgba(0, 0, 0, 0.5); } #noVNC_control_bar .noVNC_button.noVNC_selected:not(:disabled):hover { - border-color: rgba(0, 0, 0, 0.4); - background-color: rgba(0, 0, 0, 0.2); + border-color: rgba(0, 0, 0, 0.4); + background-color: rgba(0, 0, 0, 0.2); } #noVNC_control_bar .noVNC_button:not(:disabled):hover { - background-color: rgba(255, 255, 255, 0.2); + background-color: rgba(255, 255, 255, 0.2); } #noVNC_control_bar .noVNC_button:not(:disabled):active { - padding-top: 5px; - padding-bottom: 3px; + padding-top: 5px; + padding-bottom: 3px; } #noVNC_control_bar .noVNC_button.noVNC_hidden { - display: none !important; + display: none !important; } /* Android browsers don't properly update hover state if touch events are * intercepted, like they are when clicking on the remote screen. */ @media (any-pointer: coarse) { - #noVNC_control_bar .noVNC_button:not(:disabled):hover { - background-color: transparent; - } - #noVNC_control_bar .noVNC_button.noVNC_selected:not(:disabled):hover { - border-color: rgba(0, 0, 0, 0.8); - background-color: rgba(0, 0, 0, 0.5); - } + #noVNC_control_bar .noVNC_button:not(:disabled):hover { + background-color: transparent; + } + #noVNC_control_bar .noVNC_button.noVNC_selected:not(:disabled):hover { + border-color: rgba(0, 0, 0, 0.8); + background-color: rgba(0, 0, 0, 0.5); + } } /* Panels */ .noVNC_panel { - transform: translateX(25px); + transform: translateX(25px); - transition: 0.5s ease-in-out; + transition: 0.5s ease-in-out; - box-sizing: border-box; /* so max-width don't have to care about padding */ - max-width: calc(100vw - 75px - 25px); /* minus left and right margins */ - max-height: 100vh; /* Chrome is buggy with 100% */ - overflow-x: hidden; - overflow-y: auto; + box-sizing: border-box; /* so max-width don't have to care about padding */ + max-width: calc(100vw - 75px - 25px); /* minus left and right margins */ + max-height: 100vh; /* Chrome is buggy with 100% */ + overflow-x: hidden; + overflow-y: auto; - visibility: hidden; - opacity: 0; + visibility: hidden; + opacity: 0; - padding: 15px; + padding: 15px; - background: #fff; - border-radius: 10px; - color: #000; - border: 2px solid #E0E0E0; - box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); + background: #fff; + border-radius: 10px; + color: #000; + border: 2px solid #E0E0E0; + box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); } .noVNC_panel.noVNC_open { - visibility: visible; - opacity: 1; - transform: translateX(75px); + visibility: visible; + opacity: 1; + transform: translateX(75px); } .noVNC_right .noVNC_vcenter { - left: auto; - right: 0; + left: auto; + right: 0; } .noVNC_right .noVNC_panel { - transform: translateX(-25px); + transform: translateX(-25px); } .noVNC_right .noVNC_panel.noVNC_open { - transform: translateX(-75px); + transform: translateX(-75px); } .noVNC_panel > * { - display: block; - margin: 10px auto; + display: block; + margin: 10px auto; } .noVNC_panel > *:first-child { - margin-top: 0 !important; + margin-top: 0 !important; } .noVNC_panel > *:last-child { - margin-bottom: 0 !important; + margin-bottom: 0 !important; } .noVNC_panel hr { - border: none; - border-top: 1px solid rgb(192, 192, 192); + border: none; + border-top: 1px solid rgb(192, 192, 192); } .noVNC_panel label { - display: block; - white-space: nowrap; - margin: 5px; + display: block; + white-space: nowrap; + margin: 5px; } .noVNC_panel li { - margin: 5px; + margin: 5px; } .noVNC_panel .noVNC_heading { - background-color: rgb(110, 132, 163); - border-radius: 5px; - padding: 5px; - /* Compensate for padding in image */ - padding-right: 8px; - color: white; - font-size: 20px; - white-space: nowrap; + background-color: rgb(110, 132, 163); + border-radius: 5px; + padding: 5px; + /* Compensate for padding in image */ + padding-right: 8px; + color: white; + font-size: 20px; + white-space: nowrap; } .noVNC_panel .noVNC_heading img { - vertical-align: bottom; + vertical-align: bottom; } .noVNC_submit { - float: right; + float: right; } /* Expanders */ .noVNC_expander { - cursor: pointer; + cursor: pointer; } .noVNC_expander::before { - content: url("../images/expander.svg"); - display: inline-block; - margin-right: 5px; - transition: 0.2s ease-in-out; + content: url("../images/expander.svg"); + display: inline-block; + margin-right: 5px; + transition: 0.2s ease-in-out; } .noVNC_expander.noVNC_open::before { - transform: rotateZ(90deg); + transform: rotateZ(90deg); } .noVNC_expander ~ * { - margin: 5px; - margin-left: 10px; - padding: 5px; - background: rgba(0, 0, 0, 0.05); - border-radius: 5px; + margin: 5px; + margin-left: 10px; + padding: 5px; + background: rgba(0, 0, 0, 0.05); + border-radius: 5px; } .noVNC_expander:not(.noVNC_open) ~ * { - display: none; + display: none; } /* Control bar content */ #noVNC_control_bar .noVNC_logo { - font-size: 13px; + font-size: 13px; } .noVNC_logo + hr { @@ -546,92 +546,92 @@ html { } :root:not(.noVNC_connected) #noVNC_view_drag_button { - display: none; + display: none; } /* noVNC Touch Device only buttons */ :root:not(.noVNC_connected) #noVNC_mobile_buttons { - display: none; + display: none; } @media not all and (any-pointer: coarse) { - /* FIXME: The button for the virtual keyboard is the only button in this - group of "mobile buttons". It is bad to assume that no touch - devices have physical keyboards available. Hopefully we can get - a media query for this: - https://github.com/w3c/csswg-drafts/issues/3871 */ - :root.noVNC_connected #noVNC_mobile_buttons { - display: none; - } + /* FIXME: The button for the virtual keyboard is the only button in this + group of "mobile buttons". It is bad to assume that no touch + devices have physical keyboards available. Hopefully we can get + a media query for this: + https://github.com/w3c/csswg-drafts/issues/3871 */ + :root.noVNC_connected #noVNC_mobile_buttons { + display: none; + } } /* Extra manual keys */ :root:not(.noVNC_connected) #noVNC_toggle_extra_keys_button { - display: none; + display: none; } #noVNC_modifiers { - background-color: rgb(92, 92, 92); - border: none; - padding: 10px; + background-color: rgb(92, 92, 92); + border: none; + padding: 10px; } /* Shutdown/Reboot */ :root:not(.noVNC_connected) #noVNC_power_button { - display: none; + display: none; } #noVNC_power { } #noVNC_power_buttons { - display: none; + display: none; } #noVNC_power input[type=button] { - width: 100%; + width: 100%; } /* Clipboard */ :root:not(.noVNC_connected) #noVNC_clipboard_button { - display: none; + display: none; } #noVNC_clipboard_text { - width: 360px; - min-width: 150px; - height: 160px; - min-height: 70px; + width: 360px; + min-width: 150px; + height: 160px; + min-height: 70px; - box-sizing: border-box; - max-width: 100%; - /* minus approximate height of title, height of subtitle, and margin */ - max-height: calc(100vh - 10em - 25px); + box-sizing: border-box; + max-width: 100%; + /* minus approximate height of title, height of subtitle, and margin */ + max-height: calc(100vh - 10em - 25px); } /* Settings */ #noVNC_settings { } #noVNC_settings ul { - list-style: none; - padding: 0px; + list-style: none; + padding: 0px; } #noVNC_setting_port { - width: 80px; + width: 80px; } #noVNC_setting_path { - width: 100px; + width: 100px; } /* Version */ .noVNC_version_wrapper { - font-size: small; + font-size: small; } .noVNC_version { - margin-left: 1rem; + margin-left: 1rem; } /* Connection controls */ :root:not(.noVNC_connected) #noVNC_disconnect_button { - display: none; + display: none; } /* ---------------------------------------- @@ -640,64 +640,64 @@ html { */ #noVNC_status { - position: fixed; - top: 0; - left: 0; - width: 100%; - z-index: 100; - transform: translateY(-100%); + position: fixed; + top: 0; + left: 0; + width: 100%; + z-index: 100; + transform: translateY(-100%); - cursor: pointer; + cursor: pointer; - transition: 0.5s ease-in-out; + transition: 0.5s ease-in-out; - visibility: hidden; - opacity: 0; + visibility: hidden; + opacity: 0; - padding: 5px; + padding: 5px; - display: flex; - flex-direction: row; - justify-content: center; - align-content: center; + display: flex; + flex-direction: row; + justify-content: center; + align-content: center; - line-height: 1.6; - word-wrap: break-word; - color: #fff; + line-height: 1.6; + word-wrap: break-word; + color: #fff; - border-bottom: 1px solid rgba(0, 0, 0, 0.9); + border-bottom: 1px solid rgba(0, 0, 0, 0.9); } #noVNC_status.noVNC_open { - transform: translateY(0); - visibility: visible; - opacity: 1; + transform: translateY(0); + visibility: visible; + opacity: 1; } #noVNC_status::before { - content: ""; - display: inline-block; - width: 25px; - height: 25px; - margin-right: 5px; + content: ""; + display: inline-block; + width: 25px; + height: 25px; + margin-right: 5px; } #noVNC_status.noVNC_status_normal { - background: rgba(128,128,128,0.9); + background: rgba(128,128,128,0.9); } #noVNC_status.noVNC_status_normal::before { - content: url("../images/info.svg") " "; + content: url("../images/info.svg") " "; } #noVNC_status.noVNC_status_error { - background: rgba(200,55,55,0.9); + background: rgba(200,55,55,0.9); } #noVNC_status.noVNC_status_error::before { - content: url("../images/error.svg") " "; + content: url("../images/error.svg") " "; } #noVNC_status.noVNC_status_warn { - background: rgba(180,180,30,0.9); + background: rgba(180,180,30,0.9); } #noVNC_status.noVNC_status_warn::before { - content: url("../images/warning.svg") " "; + content: url("../images/warning.svg") " "; } /* ---------------------------------------- @@ -706,67 +706,67 @@ html { */ #noVNC_connect_dlg { - transition: 0.5s ease-in-out; + transition: 0.5s ease-in-out; - transform: scale(0, 0); - visibility: hidden; - opacity: 0; + transform: scale(0, 0); + visibility: hidden; + opacity: 0; } #noVNC_connect_dlg.noVNC_open { - transform: scale(1, 1); - visibility: visible; - opacity: 1; + transform: scale(1, 1); + visibility: visible; + opacity: 1; } #noVNC_connect_dlg .noVNC_logo { - transition: 0.5s ease-in-out; - padding: 10px; - margin-bottom: 10px; + transition: 0.5s ease-in-out; + padding: 10px; + margin-bottom: 10px; - font-size: 80px; - text-align: center; + font-size: 80px; + text-align: center; - border-radius: 5px; + border-radius: 5px; } @media (max-width: 440px) { - #noVNC_connect_dlg { - max-width: calc(100vw - 100px); - } - #noVNC_connect_dlg .noVNC_logo { - font-size: calc(25vw - 30px); - } + #noVNC_connect_dlg { + max-width: calc(100vw - 100px); + } + #noVNC_connect_dlg .noVNC_logo { + font-size: calc(25vw - 30px); + } } #noVNC_connect_dlg div { - padding: 12px; + padding: 12px; - background-color: rgb(110, 132, 163); - border-radius: 12px; - text-align: center; - font-size: 20px; + background-color: rgb(110, 132, 163); + border-radius: 12px; + text-align: center; + font-size: 20px; - box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); + box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); } #noVNC_connect_button { - width: 100%; - padding: 5px 30px; + width: 100%; + padding: 5px 30px; - cursor: pointer; + cursor: pointer; - border-color: rgb(83, 99, 122); - border-radius: 5px; + border-color: rgb(83, 99, 122); + border-radius: 5px; - background: linear-gradient(to top, rgb(110, 132, 163), rgb(99, 119, 147)); - color: white; + background: linear-gradient(to top, rgb(110, 132, 163), rgb(99, 119, 147)); + color: white; - /* This avoids it jumping around when :active */ - vertical-align: middle; + /* This avoids it jumping around when :active */ + vertical-align: middle; } #noVNC_connect_button:hover { - background: linear-gradient(to top, rgb(110, 132, 163), rgb(105, 125, 155)); + background: linear-gradient(to top, rgb(110, 132, 163), rgb(105, 125, 155)); } #noVNC_connect_button img { - vertical-align: bottom; - height: 1.3em; + vertical-align: bottom; + height: 1.3em; } /* ---------------------------------------- @@ -775,15 +775,15 @@ html { */ #noVNC_verify_server_dlg { - position: relative; + position: relative; - transform: translateY(-50px); + transform: translateY(-50px); } #noVNC_verify_server_dlg.noVNC_open { - transform: translateY(0); + transform: translateY(0); } #noVNC_fingerprint_block { - margin: 10px; + margin: 10px; } /* ---------------------------------------- @@ -792,16 +792,16 @@ html { */ #noVNC_credentials_dlg { - position: relative; + position: relative; - transform: translateY(-50px); + transform: translateY(-50px); } #noVNC_credentials_dlg.noVNC_open { - transform: translateY(0); + transform: translateY(0); } #noVNC_username_block.noVNC_hidden, #noVNC_password_block.noVNC_hidden { - display: none; + display: none; } @@ -812,90 +812,90 @@ html { /* Transition screen */ #noVNC_transition { - transition: 0.5s ease-in-out; + transition: 0.5s ease-in-out; - display: flex; - opacity: 0; - visibility: hidden; + display: flex; + opacity: 0; + visibility: hidden; - position: fixed; - top: 0; - left: 0; - bottom: 0; - right: 0; + position: fixed; + top: 0; + left: 0; + bottom: 0; + right: 0; - color: white; - background: rgba(0, 0, 0, 0.5); - z-index: 50; + color: white; + background: rgba(0, 0, 0, 0.5); + z-index: 50; - /*display: flex;*/ - align-items: center; - justify-content: center; - flex-direction: column; + /*display: flex;*/ + align-items: center; + justify-content: center; + flex-direction: column; } :root.noVNC_loading #noVNC_transition, :root.noVNC_connecting #noVNC_transition, :root.noVNC_disconnecting #noVNC_transition, :root.noVNC_reconnecting #noVNC_transition { - opacity: 1; - visibility: visible; + opacity: 1; + visibility: visible; } :root:not(.noVNC_reconnecting) #noVNC_cancel_reconnect_button { - display: none; + display: none; } #noVNC_transition_text { - font-size: 1.5em; + font-size: 1.5em; } /* Main container */ #noVNC_container { - width: 100%; - height: 100%; - background-color: #313131; - border-bottom-right-radius: 800px 600px; - /*border-top-left-radius: 800px 600px;*/ + width: 100%; + height: 100%; + background-color: #313131; + border-bottom-right-radius: 800px 600px; + /*border-top-left-radius: 800px 600px;*/ - /* If selection isn't disabled, long-pressing stuff in the sidebar - can accidentally select the container or the canvas. This can - happen when attempting to move the handle. */ - user-select: none; - -webkit-user-select: none; + /* If selection isn't disabled, long-pressing stuff in the sidebar + can accidentally select the container or the canvas. This can + happen when attempting to move the handle. */ + user-select: none; + -webkit-user-select: none; } #noVNC_keyboardinput { - width: 1px; - height: 1px; - background-color: #fff; - color: #fff; - border: 0; - position: absolute; - left: -40px; - z-index: -1; - ime-mode: disabled; + width: 1px; + height: 1px; + background-color: #fff; + color: #fff; + border: 0; + position: absolute; + left: -40px; + z-index: -1; + ime-mode: disabled; } /*Default noVNC logo.*/ /* From: http://fonts.googleapis.com/css?family=Orbitron:700 */ @font-face { - font-family: 'Orbitron'; - font-style: normal; - font-weight: 700; - src: local('?'), url('Orbitron700.woff') format('woff'), - url('Orbitron700.ttf') format('truetype'); + font-family: 'Orbitron'; + font-style: normal; + font-weight: 700; + src: local('?'), url('Orbitron700.woff') format('woff'), + url('Orbitron700.ttf') format('truetype'); } .noVNC_logo { - color:yellow; - font-family: 'Orbitron', 'OrbitronTTF', sans-serif; - line-height: 0.9; - text-shadow: 0.1em 0.1em 0 black; + color:yellow; + font-family: 'Orbitron', 'OrbitronTTF', sans-serif; + line-height: 0.9; + text-shadow: 0.1em 0.1em 0 black; } .noVNC_logo span{ - color:green; + color:green; } #noVNC_bell { - display: none; + display: none; } /* ---------------------------------------- @@ -904,19 +904,19 @@ html { */ @media screen and (max-width: 640px){ - #noVNC_logo { - font-size: 150px; - } + #noVNC_logo { + font-size: 150px; + } } @media screen and (min-width: 321px) and (max-width: 480px) { - #noVNC_logo { - font-size: 110px; - } + #noVNC_logo { + font-size: 110px; + } } @media screen and (max-width: 320px) { - #noVNC_logo { - font-size: 90px; - } + #noVNC_logo { + font-size: 90px; + } } diff --git a/app/styles/input.css b/app/styles/input.css index 911cf20..a0cba47 100644 --- a/app/styles/input.css +++ b/app/styles/input.css @@ -9,19 +9,19 @@ * Common for all inputs */ input, input::file-selector-button, button, select, textarea { - /* Respect standard font settings */ - font: inherit; + /* Respect standard font settings */ + font: inherit; - /* Disable default rendering */ - appearance: none; - background: none; + /* Disable default rendering */ + appearance: none; + background: none; - padding: 5px; - border: 1px solid rgb(192, 192, 192); - border-radius: 5px; - color: black; - --bg-gradient: linear-gradient(to top, rgb(255, 255, 255) 80%, rgb(240, 240, 240)); - background-image: var(--bg-gradient); + padding: 5px; + border: 1px solid rgb(192, 192, 192); + border-radius: 5px; + color: black; + --bg-gradient: linear-gradient(to top, rgb(255, 255, 255) 80%, rgb(240, 240, 240)); + background-image: var(--bg-gradient); } /* @@ -35,151 +35,151 @@ input[type=submit], input::file-selector-button, button, select { - border-bottom-width: 2px; + border-bottom-width: 2px; - /* This avoids it jumping around when :active */ - vertical-align: middle; - margin-top: 0; + /* This avoids it jumping around when :active */ + vertical-align: middle; + margin-top: 0; - padding-left: 20px; - padding-right: 20px; + padding-left: 20px; + padding-right: 20px; - /* Disable Chrome's touch tap highlight */ - -webkit-tap-highlight-color: transparent; + /* Disable Chrome's touch tap highlight */ + -webkit-tap-highlight-color: transparent; } /* * Select dropdowns */ select { - --select-arrow: url('data:image/svg+xml;utf8, \ - \ - \ - '); - background-image: var(--select-arrow), var(--bg-gradient); - background-position: calc(100% - 7px), left top; - background-repeat: no-repeat; - padding-right: calc(2*7px + 8px); - padding-left: 7px; + --select-arrow: url('data:image/svg+xml;utf8, \ + \ + \ + '); + background-image: var(--select-arrow), var(--bg-gradient); + background-position: calc(100% - 7px), left top; + background-repeat: no-repeat; + padding-right: calc(2*7px + 8px); + padding-left: 7px; } /* FIXME: :active isn't set when the is opened in Firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=1805406 */ From 72cac2ef6a6f5f4536fcb2ec2f430a78bd0a9194 Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Sat, 11 Jan 2025 23:20:33 +0100 Subject: [PATCH 03/38] Add margin between label and input in noVNC_panel To make stuff feel less cramped, lets add some margin here. As of comitting this, it only affects the logging-level select dropdown in the settings, but this is a general rule of thumb. It doesn't apply to checkboxes or radios since they have a margin by default, and their label to the left. --- app/styles/base.css | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/styles/base.css b/app/styles/base.css index 06e3d5a..f2f4986 100644 --- a/app/styles/base.css +++ b/app/styles/base.css @@ -491,6 +491,13 @@ html { margin: 5px; } +.noVNC_panel label > button, +.noVNC_panel label > select, +.noVNC_panel label > textarea, +.noVNC_panel label > input:not([type=checkbox]):not([type=radio]) { + margin-left: 6px; +} + .noVNC_panel .noVNC_heading { background-color: rgb(110, 132, 163); border-radius: 5px; From 7603ced54e9e73fb969b705da50716699fbee608 Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Sun, 12 Jan 2025 00:09:25 +0100 Subject: [PATCH 04/38] Create CSS variables for common noVNC-colors --- app/styles/base.css | 26 +++++++++++++------------- app/styles/constants.css | 21 +++++++++++++++++++++ app/styles/input.css | 14 +++++++------- vnc.html | 1 + 4 files changed, 42 insertions(+), 20 deletions(-) create mode 100644 app/styles/constants.css diff --git a/app/styles/base.css b/app/styles/base.css index f2f4986..ecef377 100644 --- a/app/styles/base.css +++ b/app/styles/base.css @@ -53,7 +53,7 @@ html { } .noVNC_disabled { - color: rgb(128, 128, 128); + color: var(--novnc-grey); } /* ---------------------------------------- @@ -241,7 +241,7 @@ html { transition: 0.5s ease-in-out; - background-color: rgb(110, 132, 163); + background-color: var(--novnc-blue); border-radius: 0 10px 10px 0; user-select: none; @@ -286,7 +286,7 @@ html { z-index: -1; cursor: pointer; border-radius: 5px; - background-color: rgb(83, 99, 122); + background-color: var(--novnc-darkblue); background-image: url("../images/handle_bg.svg"); background-repeat: no-repeat; background-position: right; @@ -371,7 +371,7 @@ html { opacity: 0; transition: 0.2s ease-in-out; background: transparent; - box-shadow: 0 0 10px black, inset 0 0 10px 10px rgba(110, 132, 163, 0.8); + box-shadow: 0 0 10px black, inset 0 0 10px 10px var(--novnc-darkblue); border-radius: 10px; transition-delay: 0s; } @@ -478,7 +478,7 @@ html { .noVNC_panel hr { border: none; - border-top: 1px solid rgb(192, 192, 192); + border-top: 1px solid var(--novnc-lightgrey); } .noVNC_panel label { @@ -499,7 +499,7 @@ html { } .noVNC_panel .noVNC_heading { - background-color: rgb(110, 132, 163); + background-color: var(--novnc-blue); border-radius: 5px; padding: 5px; /* Compensate for padding in image */ @@ -577,7 +577,7 @@ html { } #noVNC_modifiers { - background-color: rgb(92, 92, 92); + background-color: var(--novnc-darkgrey); border: none; padding: 10px; } @@ -745,7 +745,7 @@ html { #noVNC_connect_dlg div { padding: 12px; - background-color: rgb(110, 132, 163); + background-color: var(--novnc-blue); border-radius: 12px; text-align: center; font-size: 20px; @@ -758,17 +758,17 @@ html { cursor: pointer; - border-color: rgb(83, 99, 122); + border-color: var(--novnc-darkblue); border-radius: 5px; - background: linear-gradient(to top, rgb(110, 132, 163), rgb(99, 119, 147)); + background: linear-gradient(to top, var(--novnc-blue), rgb(99, 119, 147)); color: white; /* This avoids it jumping around when :active */ vertical-align: middle; } #noVNC_connect_button:hover { - background: linear-gradient(to top, rgb(110, 132, 163), rgb(105, 125, 155)); + background: linear-gradient(to top, var(--novnc-blue), rgb(105, 125, 155)); } #noVNC_connect_button img { @@ -892,13 +892,13 @@ html { } .noVNC_logo { - color:yellow; + color: var(--novnc-yellow); font-family: 'Orbitron', 'OrbitronTTF', sans-serif; line-height: 0.9; text-shadow: 0.1em 0.1em 0 black; } .noVNC_logo span{ - color:green; + color: var(--novnc-green); } #noVNC_bell { diff --git a/app/styles/constants.css b/app/styles/constants.css new file mode 100644 index 0000000..fb1f550 --- /dev/null +++ b/app/styles/constants.css @@ -0,0 +1,21 @@ +/* + * noVNC general CSS constant variables + * Copyright (C) 2025 The noVNC authors + * noVNC is licensed under the MPL 2.0 (see LICENSE.txt) + * This file is licensed under the 2-Clause BSD license (see LICENSE.txt). + */ + +/* ---------- COLORS ----------- */ + +:root { + --novnc-grey: rgb(128, 128, 128); + --novnc-lightgrey: rgb(192, 192, 192); + --novnc-darkgrey: rgb(92, 92, 92); + + --novnc-blue: rgb(110, 132, 163); + --novnc-lightblue: rgb(74, 144, 217); + --novnc-darkblue: rgb(83, 99, 122); + + --novnc-green: rgb(0, 128, 0); + --novnc-yellow: rgb(255, 255, 0); +} diff --git a/app/styles/input.css b/app/styles/input.css index fc36e71..a2b289b 100644 --- a/app/styles/input.css +++ b/app/styles/input.css @@ -21,7 +21,7 @@ input, input::file-selector-button, button, select, textarea { background: none; padding: 0.5em var(--input-xpadding); - border: 1px solid rgb(192, 192, 192); + border: 1px solid var(--novnc-lightgrey); border-radius: 5px; color: black; --bg-gradient: linear-gradient(to top, rgb(255, 255, 255) 80%, rgb(240, 240, 240)); @@ -101,8 +101,8 @@ input[type=checkbox] { transition: 0.2s background-color linear; } input[type=checkbox]:checked { - background-color: rgb(110, 132, 163); - border-color: rgb(110, 132, 163); + background-color: var(--novnc-blue); + border-color: var(--novnc-blue); } input[type=checkbox]:checked::after { content: ""; @@ -127,7 +127,7 @@ input[type=radio] { transition: 0.2s border linear; } input[type=radio]:checked { - border: 6px solid rgb(110, 132, 163); + border: 6px solid var(--novnc-blue); } /* @@ -143,12 +143,12 @@ input[type=range] { /* -webkit-slider.. & -moz-range.. cant be in selector lists: https://bugs.chromium.org/p/chromium/issues/detail?id=1154623 */ input[type=range]::-webkit-slider-runnable-track { - background-color: rgb(110, 132, 163); + background-color: var(--novnc-blue); height: 6px; border-radius: 3px; } input[type=range]::-moz-range-track { - background-color: rgb(110, 132, 163); + background-color: var(--novnc-blue); height: 6px; border-radius: 3px; } @@ -239,7 +239,7 @@ input:focus-visible::file-selector-button, button:focus-visible, select:focus-visible, textarea:focus-visible { - outline: 2px solid rgb(74, 144, 217); + outline: 2px solid var(--novnc-lightblue); outline-offset: 1px; } input[type=file]:focus-visible { diff --git a/vnc.html b/vnc.html index c2cc4e5..ed82b60 100644 --- a/vnc.html +++ b/vnc.html @@ -37,6 +37,7 @@ + From ca270efcc36a8f6df97d44977d14bb64693a6217 Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Sun, 12 Jan 2025 00:36:44 +0100 Subject: [PATCH 05/38] Standardize on 6px or 12px border-radius This results in a few things becoming slighly more rounded, for example the controlbar, the settings panel and buttons/inputs. Increased rounding gives a more friendly feel. --- app/styles/base.css | 20 ++++++++++---------- app/styles/input.css | 6 +++--- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/app/styles/base.css b/app/styles/base.css index ecef377..de2624f 100644 --- a/app/styles/base.css +++ b/app/styles/base.css @@ -174,7 +174,7 @@ html { font-weight: bold; color: #fff; - border-radius: 10px; + border-radius: 12px; box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); background: rgba(200,55,55,0.8); } @@ -242,7 +242,7 @@ html { transition: 0.5s ease-in-out; background-color: var(--novnc-blue); - border-radius: 0 10px 10px 0; + border-radius: 0 12px 12px 0; user-select: none; -webkit-user-select: none; @@ -267,7 +267,7 @@ html { } .noVNC_right #noVNC_control_bar { left: 100%; - border-radius: 10px 0 0 10px; + border-radius: 12px 0 0 12px; } .noVNC_right #noVNC_control_bar.noVNC_open { left: 0; @@ -285,7 +285,7 @@ html { height: 50px; z-index: -1; cursor: pointer; - border-radius: 5px; + border-radius: 6px; background-color: var(--novnc-darkblue); background-image: url("../images/handle_bg.svg"); background-repeat: no-repeat; @@ -372,7 +372,7 @@ html { transition: 0.2s ease-in-out; background: transparent; box-shadow: 0 0 10px black, inset 0 0 10px 10px var(--novnc-darkblue); - border-radius: 10px; + border-radius: 12px; transition-delay: 0s; } #noVNC_control_bar_hint.noVNC_active { @@ -444,7 +444,7 @@ html { padding: 15px; background: #fff; - border-radius: 10px; + border-radius: 12px; color: #000; border: 2px solid #E0E0E0; box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); @@ -500,7 +500,7 @@ html { .noVNC_panel .noVNC_heading { background-color: var(--novnc-blue); - border-radius: 5px; + border-radius: 6px; padding: 5px; /* Compensate for padding in image */ padding-right: 8px; @@ -534,7 +534,7 @@ html { margin-left: 10px; padding: 5px; background: rgba(0, 0, 0, 0.05); - border-radius: 5px; + border-radius: 6px; } .noVNC_expander:not(.noVNC_open) ~ * { display: none; @@ -732,7 +732,7 @@ html { font-size: 80px; text-align: center; - border-radius: 5px; + border-radius: 6px; } @media (max-width: 440px) { #noVNC_connect_dlg { @@ -759,7 +759,7 @@ html { cursor: pointer; border-color: var(--novnc-darkblue); - border-radius: 5px; + border-radius: 6px; background: linear-gradient(to top, var(--novnc-blue), rgb(99, 119, 147)); color: white; diff --git a/app/styles/input.css b/app/styles/input.css index a2b289b..2be7fe4 100644 --- a/app/styles/input.css +++ b/app/styles/input.css @@ -22,7 +22,7 @@ input, input::file-selector-button, button, select, textarea { padding: 0.5em var(--input-xpadding); border: 1px solid var(--novnc-lightgrey); - border-radius: 5px; + border-radius: 6px; color: black; --bg-gradient: linear-gradient(to top, rgb(255, 255, 255) 80%, rgb(240, 240, 240)); background-image: var(--bg-gradient); @@ -156,7 +156,7 @@ input[type=range]::-webkit-slider-thumb { appearance: none; width: 18px; height: 20px; - border-radius: 5px; + border-radius: 6px; background-color: white; border: 1px solid dimgray; margin-top: -7px; @@ -165,7 +165,7 @@ input[type=range]::-moz-range-thumb { appearance: none; width: 18px; height: 20px; - border-radius: 5px; + border-radius: 6px; background-color: white; border: 1px solid dimgray; margin-top: -7px; From e9b48ae40938865fa83ebd2d39b25d64f92582b2 Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Sun, 12 Jan 2025 01:29:06 +0100 Subject: [PATCH 06/38] Get rid of gradients on buttons and inputs Lets make things more flat and modern. --- app/styles/base.css | 4 ++-- app/styles/input.css | 29 ++++++++++++++--------------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/app/styles/base.css b/app/styles/base.css index de2624f..3c96933 100644 --- a/app/styles/base.css +++ b/app/styles/base.css @@ -761,14 +761,14 @@ html { border-color: var(--novnc-darkblue); border-radius: 6px; - background: linear-gradient(to top, var(--novnc-blue), rgb(99, 119, 147)); + background-color: var(--novnc-blue); color: white; /* This avoids it jumping around when :active */ vertical-align: middle; } #noVNC_connect_button:hover { - background: linear-gradient(to top, var(--novnc-blue), rgb(105, 125, 155)); + background-color: var(--novnc-darkblue); } #noVNC_connect_button img { diff --git a/app/styles/input.css b/app/styles/input.css index 2be7fe4..1a51e54 100644 --- a/app/styles/input.css +++ b/app/styles/input.css @@ -18,14 +18,10 @@ input, input::file-selector-button, button, select, textarea { /* Disable default rendering */ appearance: none; - background: none; padding: 0.5em var(--input-xpadding); border: 1px solid var(--novnc-lightgrey); border-radius: 6px; - color: black; - --bg-gradient: linear-gradient(to top, rgb(255, 255, 255) 80%, rgb(240, 240, 240)); - background-image: var(--bg-gradient); } /* @@ -44,6 +40,8 @@ select { /* This avoids it jumping around when :active */ vertical-align: middle; margin-top: 0; + color: black; + background-color: white; /* Disable Chrome's touch tap highlight */ -webkit-tap-highlight-color: transparent; @@ -60,7 +58,8 @@ select { stroke="rgb(31,31,31)" fill="none" \ stroke-linecap="round" stroke-linejoin="round" /> \ '); - background-image: var(--select-arrow), var(--bg-gradient); + background-color: white; + background-image: var(--select-arrow); background-position: calc(100% - var(--input-xpadding)), left top, left top; background-repeat: no-repeat; padding-right: calc(2*var(--input-xpadding) + 8px); @@ -75,7 +74,7 @@ select:active { \ - '), var(--bg-gradient); + '); } option { color: black; @@ -192,13 +191,13 @@ input[type=reset]:hover, input[type=submit]:hover, input::file-selector-button:hover, button:hover { - background-image: linear-gradient(to top, rgb(255, 255, 255), rgb(250, 250, 250)); + background-color: var(--novnc-lightgrey); } select:hover { - background-image: var(--select-arrow), - linear-gradient(to top, rgb(255, 255, 255), rgb(250, 250, 250)); - background-position: calc(100% - 7px), left top; - background-repeat: no-repeat; + background-image: + var(--select-arrow), + linear-gradient(var(--novnc-lightgrey) 100%, + transparent); } @media (any-pointer: coarse) { /* We don't want a hover style after touch input */ @@ -209,10 +208,10 @@ select:hover { input[type=submit]:hover, input::file-selector-button:hover, button:hover { - background-image: var(--bg-gradient); + background-color: white; } select:hover { - background-image: var(--select-arrow), var(--bg-gradient); + background-image: var(--select-arrow); } } @@ -264,7 +263,7 @@ input[type=submit]:disabled, input:disabled::file-selector-button, button:disabled, select:disabled { - background-image: var(--bg-gradient); + background-color: white; border-bottom-width: 2px; margin-top: 0; } @@ -272,7 +271,7 @@ input[type=file]:disabled { background-image: none; } select:disabled { - background-image: var(--select-arrow), var(--bg-gradient); + background-image: var(--select-arrow), } input[type=image]:disabled { /* See Firefox bug: From 3f29c9d9930cf5f6b67cb6692477948bb441ea2c Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Sun, 12 Jan 2025 01:37:19 +0100 Subject: [PATCH 07/38] Differentiate buttons from text inputs By making buttons grey with bold text, they are easy to distinguish from text inputs. --- app/styles/constants.css | 3 +++ app/styles/input.css | 34 ++++++++++++++++++++++++++-------- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/app/styles/constants.css b/app/styles/constants.css index fb1f550..daf3961 100644 --- a/app/styles/constants.css +++ b/app/styles/constants.css @@ -12,6 +12,9 @@ --novnc-lightgrey: rgb(192, 192, 192); --novnc-darkgrey: rgb(92, 92, 92); + /* Transparent to make button colors adapt to the background */ + --novnc-buttongrey: rgba(192, 192, 192, 0.5); + --novnc-blue: rgb(110, 132, 163); --novnc-lightblue: rgb(74, 144, 217); --novnc-darkblue: rgb(83, 99, 122); diff --git a/app/styles/input.css b/app/styles/input.css index 1a51e54..e2468ae 100644 --- a/app/styles/input.css +++ b/app/styles/input.css @@ -41,7 +41,8 @@ select { vertical-align: middle; margin-top: 0; color: black; - background-color: white; + font-weight: bold; + background-color: var(--novnc-buttongrey); /* Disable Chrome's touch tap highlight */ -webkit-tap-highlight-color: transparent; @@ -58,8 +59,18 @@ select { stroke="rgb(31,31,31)" fill="none" \ stroke-linecap="round" stroke-linejoin="round" /> \ '); + /* FIXME: A bug in Firefox, requires a workaround for the background: + https://bugzilla.mozilla.org/show_bug.cgi?id=1810958 */ + /* The dropdown list will show the select element's background above and + below the options in Firefox. We want the entire dropdown to be white. */ background-color: white; - background-image: var(--select-arrow); + /* However, we don't want the select element to actually show a white + background, so let's place a gradient above it with the color we want. */ + --grey-background: linear-gradient(var(--novnc-buttongrey) 100%, + transparent); + background-image: + var(--select-arrow), + var(--grey-background); background-position: calc(100% - var(--input-xpadding)), left top, left top; background-repeat: no-repeat; padding-right: calc(2*var(--input-xpadding) + 8px); @@ -74,11 +85,14 @@ select:active { \ - '); + '), + var(--grey-background); } option { + /* Prevent Chrome from inheriting background-color from the is opened in Firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=1805406 */ select:active { /* Rotated arrow */ background-image: url('data:image/svg+xml;utf8, \ - \ - \ + \ + \ '), var(--grey-background); } From 633b4c266d8167e565e6f81d9ece8c022b1bfae7 Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Sun, 12 Jan 2025 02:06:51 +0100 Subject: [PATCH 09/38] Redesign checkboxes and radiobuttons Makes them bigger and gets rid of their borders. The change also allowed for some shared styling between them. --- app/styles/input.css | 100 ++++++++++++++++++++++++++++++++----------- 1 file changed, 75 insertions(+), 25 deletions(-) diff --git a/app/styles/input.css b/app/styles/input.css index f206a65..d9b9067 100644 --- a/app/styles/input.css +++ b/app/styles/input.css @@ -97,35 +97,80 @@ option { } /* - * Checkboxes + * Shared between checkboxes and radiobuttons */ + +input[type=radio], input[type=checkbox] { display: inline-flex; justify-content: center; align-items: center; - background-color: white; - background-image: unset; - border: 1px solid dimgrey; - border-radius: 3px; - width: 13px; - height: 13px; + border-color: transparent; + background-color: var(--novnc-buttongrey); + /* Disable Chrome's touch tap highlight to avoid conflicts with overlay */ + -webkit-tap-highlight-color: transparent; + width: 16px; + --checkradio-height: 16px; + height: var(--checkradio-height); padding: 0; - margin-right: 6px; - vertical-align: bottom; - transition: 0.2s background-color linear; + margin: 0 6px 0 0; + /* Don't have transitions for outline in order to be consistent + with other elements */ + transition: all 0.2s, outline-color 0s, outline-offset 0s; + + /* A transparent outline in order to work around a graphical clipping issue + in WebKit. See bug: https://bugs.webkit.org/show_bug.cgi?id=256003 */ + outline: 1px solid transparent; + position: relative; /* Since ::before & ::after are absolute positioned */ + + /* We want to align with the middle of capital letters, this requires + a workaround. The default behavior is to align the bottom of the element + on top of the text baseline, this is too far up. + We want to push the element down half the difference in height between + it and a capital X. In our font, the height of a capital "X" is 0.698em. + */ + vertical-align: calc(0px - (var(--checkradio-height) - 0.698em) / 2); + /* FIXME: Could write 1cap instead of 0.698em, but it's only supported in + Firefox as of 2023 */ + /* FIXME: We probably want to use round() here, see bug 8148 */ +} +input[type=radio]:focus-visible, +input[type=checkbox]:focus-visible { + outline-color: var(--novnc-lightblue); +} +input[type=checkbox]::before, +input[type=radio]::before { + content: ""; + display: block; /* width & height doesn't work on inline elements */ + transition: inherit; + /* Let's prevent the pseudo-elements from taking up layout space so that + the ::before and ::after pseudo-elements can be in the same place. This + is also required for vertical-align: baseline to work like we want it to + on radio/checkboxes. If the pseudo-elements take up layout space, the + baseline of text inside them will be used instead. */ + position: absolute; +} + +/* + * Checkboxes + */ +input[type=checkbox] { + border-radius: 4px; } input[type=checkbox]:checked { background-color: var(--novnc-blue); - border-color: var(--novnc-blue); } -input[type=checkbox]:checked::after { - content: ""; - display: block; /* width & height doesn't work on inline elements */ - width: 3px; - height: 7px; - border: 1px solid white; +input[type=checkbox]::before { + width: 25%; + height: 55%; + border-style: solid; + border-color: transparent; border-width: 0 2px 2px 0; - transform: rotate(40deg) translateY(-1px); + border-radius: 1px; + transform: translateY(-1px) rotate(35deg); +} +input[type=checkbox]:checked::before { + border-color: white; } /* @@ -133,15 +178,20 @@ input[type=checkbox]:checked::after { */ input[type=radio] { border-radius: 50%; - border: 1px solid dimgrey; - width: 12px; - height: 12px; - padding: 0; - margin-right: 6px; - transition: 0.2s border linear; + border: 1px solid transparent; /* To ensure a smooth transition */ } input[type=radio]:checked { - border: 6px solid var(--novnc-blue); + border: 4px solid var(--novnc-blue); + background-color: white; +} +input[type=radio]::before { + width: inherit; + height: inherit; + border-radius: inherit; + opacity: 0; +} +input[type=radio]:checked::before { + opacity: 1; } /* From 7fdcc66d2c924baa984e83f04f759387ba132747 Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Sun, 12 Jan 2025 02:10:12 +0100 Subject: [PATCH 10/38] Add indeterminate styling to checkboxes and radios This is used when the control is neither checked or unchecked. --- app/styles/input.css | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/app/styles/input.css b/app/styles/input.css index d9b9067..7aa3dc7 100644 --- a/app/styles/input.css +++ b/app/styles/input.css @@ -139,7 +139,9 @@ input[type=checkbox]:focus-visible { outline-color: var(--novnc-lightblue); } input[type=checkbox]::before, -input[type=radio]::before { +input[type=checkbox]::after, +input[type=radio]::before, +input[type=radio]::after { content: ""; display: block; /* width & height doesn't work on inline elements */ transition: inherit; @@ -150,6 +152,13 @@ input[type=radio]::before { baseline of text inside them will be used instead. */ position: absolute; } +input[type=checkbox]::after, +input[type=radio]::after { + width: 10px; + height: 2px; + background-color: transparent; + border-radius: 2px; +} /* * Checkboxes @@ -157,7 +166,8 @@ input[type=radio]::before { input[type=checkbox] { border-radius: 4px; } -input[type=checkbox]:checked { +input[type=checkbox]:checked, +input[type=checkbox]:indeterminate { background-color: var(--novnc-blue); } input[type=checkbox]::before { @@ -172,6 +182,9 @@ input[type=checkbox]::before { input[type=checkbox]:checked::before { border-color: white; } +input[type=checkbox]:indeterminate::after { + background-color: white; +} /* * Radiobuttons @@ -193,6 +206,9 @@ input[type=radio]::before { input[type=radio]:checked::before { opacity: 1; } +input[type=radio]:indeterminate::after { + background-color: black; +} /* * Range sliders From 017888c9a8fd07f62403103eec42340233faac44 Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Sun, 12 Jan 2025 02:29:26 +0100 Subject: [PATCH 11/38] Rework how buttons react to :hover and :active Instead of having two different types of effects (hover had a different color, and active had a 3d-effect simulating a pressed button), we now have an increasing activation-level. That means the button goes a bit dark for hover, and then even darker when pressed. There is also a variant that goes lighter for each activation level, that can be used when the initial color is dark. With this change, we can get rid of special :hover and :active styling for the connect button and the control bar buttons. We can use the same activation level principle for all buttons. --- app/styles/base.css | 31 --------- app/styles/input.css | 155 ++++++++++++++++++++++++------------------- 2 files changed, 85 insertions(+), 101 deletions(-) diff --git a/app/styles/base.css b/app/styles/base.css index 3c96933..fba8981 100644 --- a/app/styles/base.css +++ b/app/styles/base.css @@ -392,40 +392,15 @@ html { border:1px solid rgba(255, 255, 255, 0.2); border-radius: 6px; background-color: transparent; - background-image: unset; /* we don't want the gradiant from input.css */ } #noVNC_control_bar .noVNC_button.noVNC_selected { border-color: rgba(0, 0, 0, 0.8); background-color: rgba(0, 0, 0, 0.5); } -#noVNC_control_bar .noVNC_button.noVNC_selected:not(:disabled):hover { - border-color: rgba(0, 0, 0, 0.4); - background-color: rgba(0, 0, 0, 0.2); -} -#noVNC_control_bar .noVNC_button:not(:disabled):hover { - background-color: rgba(255, 255, 255, 0.2); -} -#noVNC_control_bar .noVNC_button:not(:disabled):active { - padding-top: 5px; - padding-bottom: 3px; -} #noVNC_control_bar .noVNC_button.noVNC_hidden { display: none !important; } -/* Android browsers don't properly update hover state if touch events are - * intercepted, like they are when clicking on the remote screen. */ -@media (any-pointer: coarse) { - #noVNC_control_bar .noVNC_button:not(:disabled):hover { - background-color: transparent; - } - #noVNC_control_bar .noVNC_button.noVNC_selected:not(:disabled):hover { - border-color: rgba(0, 0, 0, 0.8); - background-color: rgba(0, 0, 0, 0.5); - } -} - - /* Panels */ .noVNC_panel { transform: translateX(25px); @@ -763,12 +738,6 @@ html { background-color: var(--novnc-blue); color: white; - - /* This avoids it jumping around when :active */ - vertical-align: middle; -} -#noVNC_connect_button:hover { - background-color: var(--novnc-darkblue); } #noVNC_connect_button img { diff --git a/app/styles/input.css b/app/styles/input.css index 7aa3dc7..e4c5b1a 100644 --- a/app/styles/input.css +++ b/app/styles/input.css @@ -24,6 +24,71 @@ input, input::file-selector-button, button, select, textarea { border-radius: 6px; } +/* + * Button activations + */ + +/* A color overlay that depends on the activation level. The level can then be + set for different states on an element, for example hover and click on a + '), + var(--button-activation-overlay), var(--grey-background); } option { @@ -94,6 +158,7 @@ option { background-color: white; color: black; font-weight: normal; + background-image: var(--button-activation-overlay); } /* @@ -107,6 +172,7 @@ input[type=checkbox] { align-items: center; border-color: transparent; background-color: var(--novnc-buttongrey); + background-image: var(--button-activation-overlay); /* Disable Chrome's touch tap highlight to avoid conflicts with overlay */ -webkit-tap-highlight-color: transparent; width: 16px; @@ -169,6 +235,8 @@ input[type=checkbox] { input[type=checkbox]:checked, input[type=checkbox]:indeterminate { background-color: var(--novnc-blue); + background-image: var(--button-activation-overlay-light); + background-blend-mode: overlay; } input[type=checkbox]::before { width: 25%; @@ -196,11 +264,20 @@ input[type=radio] { input[type=radio]:checked { border: 4px solid var(--novnc-blue); background-color: white; + /* button-activation-overlay should be removed from the radio + element to not interfere with button-activation-overlay-light + that is set on the ::before element. */ + background-image: none; } input[type=radio]::before { width: inherit; height: inherit; border-radius: inherit; + /* We can achieve the highlight overlay effect on border colors by + setting button-activation-overlay-light on an element that stays + on top (z-axis) of the element with a border. */ + background-image: var(--button-activation-overlay-light); + mix-blend-mode: overlay; opacity: 0; } input[type=radio]:checked::before { @@ -238,6 +315,9 @@ input[type=range]::-webkit-slider-thumb { height: 20px; border-radius: 6px; background-color: white; + background-image: var(--button-activation-overlay); + /* Disable Chrome's touch tap highlight to avoid conflicts with overlay */ + -webkit-tap-highlight-color: transparent; border: 1px solid dimgray; margin-top: -7px; } @@ -247,6 +327,7 @@ input[type=range]::-moz-range-thumb { height: 20px; border-radius: 6px; background-color: white; + background-image: var(--button-activation-overlay); border: 1px solid dimgray; margin-top: -7px; } @@ -262,57 +343,6 @@ input::file-selector-button { margin-right: 6px; } -/* - * Hover - */ -input[type=button]:hover, -input[type=color]:hover, -input[type=image]:hover, -input[type=reset]:hover, -input[type=submit]:hover, -input::file-selector-button:hover, -button:hover { - background-color: var(--novnc-lightgrey); -} -select:hover { - background-image: - var(--select-arrow), - linear-gradient(var(--novnc-lightgrey) 100%, - transparent); -} -@media (any-pointer: coarse) { - /* We don't want a hover style after touch input */ - input[type=button]:hover, - input[type=color]:hover, - input[type=image]:hover, - input[type=reset]:hover, - input[type=submit]:hover, - input::file-selector-button:hover, - button:hover { - background-color: var(--novnc-buttongrey); - } - select:hover { - background-image: - var(--select-arrow), - var(--grey-background); - } -} - -/* - * Active (clicked) - */ -input[type=button]:active, -input[type=color]:active, -input[type=image]:active, -input[type=reset]:active, -input[type=submit]:active, -input::file-selector-button:active, -button:active, -select:active { - border-bottom-width: 1px; - margin-top: 1px; -} - /* * Focus (tab) */ @@ -338,21 +368,6 @@ select:disabled, textarea:disabled { opacity: 0.4; } -input[type=button]:disabled, -input[type=color]:disabled, -input[type=image]:disabled, -input[type=reset]:disabled, -input[type=submit]:disabled, -input:disabled::file-selector-button, -button:disabled, -select:disabled { - background-color: var(--novnc-buttongrey); - border-bottom-width: 2px; - margin-top: 0; -} -input[type=file]:disabled { - background-image: none; -} select:disabled { background-image: var(--select-arrow), From 33a2548fcb4d9c437b90b08c6b951755995bd577 Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Sun, 12 Jan 2025 02:49:35 +0100 Subject: [PATCH 12/38] Make buttons flat by removing borders Gives a more clean look that fits well with the new checkboxes and radios. The old border was mostly used to contribute to a 3d-effect, that was used for :active. That :active-styling has been replaced by activation levels. --- app/styles/base.css | 7 ++----- app/styles/input.css | 35 +++++++++++++++++++++++++++-------- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/app/styles/base.css b/app/styles/base.css index fba8981..c9e60bd 100644 --- a/app/styles/base.css +++ b/app/styles/base.css @@ -729,13 +729,10 @@ html { } #noVNC_connect_button { width: 100%; - padding: 5px 30px; - + padding: 6px 30px; cursor: pointer; - - border-color: var(--novnc-darkblue); + border-color: transparent; border-radius: 6px; - background-color: var(--novnc-blue); color: white; } diff --git a/app/styles/input.css b/app/styles/input.css index e4c5b1a..7608f91 100644 --- a/app/styles/input.css +++ b/app/styles/input.css @@ -13,15 +13,35 @@ } input, input::file-selector-button, button, select, textarea { - /* Respect standard font settings */ - font: inherit; - - /* Disable default rendering */ + padding: 0.5em var(--input-xpadding); + border-radius: 6px; appearance: none; - padding: 0.5em var(--input-xpadding); + /* Respect standard font settings */ + font: inherit; +} + +/* + * Text input + */ + +input:not([type]), +input[type=date], +input[type=datetime-local], +input[type=email], +input[type=month], +input[type=number], +input[type=password], +input[type=search], +input[type=tel], +input[type=text], +input[type=time], +input[type=url], +input[type=week], +textarea { border: 1px solid var(--novnc-lightgrey); - border-radius: 6px; + /* Account for borders on text inputs, buttons dont have borders */ + padding: calc(0.5em - 1px) var(--input-xpadding); } /* @@ -100,7 +120,7 @@ input[type=submit], input::file-selector-button, button, select { - border-bottom-width: 2px; + border: none; color: black; font-weight: bold; background-color: var(--novnc-buttongrey); @@ -170,7 +190,6 @@ input[type=checkbox] { display: inline-flex; justify-content: center; align-items: center; - border-color: transparent; background-color: var(--novnc-buttongrey); background-image: var(--button-activation-overlay); /* Disable Chrome's touch tap highlight to avoid conflicts with overlay */ From 30d46a00fa3e99610f5acc54b2bdc7576bf10e9e Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Sun, 12 Jan 2025 19:50:10 +0100 Subject: [PATCH 13/38] Fix :disabled styling of file-selector-button By applying the rule to the button within the input, we effectively applied the opacity twice - making the button almost disappear. Applying the opacity to the input element is enough. --- app/styles/input.css | 1 - 1 file changed, 1 deletion(-) diff --git a/app/styles/input.css b/app/styles/input.css index 7608f91..dda08b6 100644 --- a/app/styles/input.css +++ b/app/styles/input.css @@ -381,7 +381,6 @@ input[type=file]:focus-visible { * Disabled */ input:disabled, -input:disabled::file-selector-button, button:disabled, select:disabled, textarea:disabled { From ee08032fe74828962f07422eab02ac3115e2a261 Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Sun, 12 Jan 2025 19:52:26 +0100 Subject: [PATCH 14/38] Put specific :disabled rules with its element It makes more sense to group rules per element type. --- app/styles/input.css | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/styles/input.css b/app/styles/input.css index dda08b6..d9c3504 100644 --- a/app/styles/input.css +++ b/app/styles/input.css @@ -129,6 +129,11 @@ select { /* Disable Chrome's touch tap highlight */ -webkit-tap-highlight-color: transparent; } +input[type=image]:disabled { + /* See Firefox bug: + https://bugzilla.mozilla.org/show_bug.cgi?id=1798304 */ + cursor: default; +} /* * Select dropdowns @@ -173,6 +178,11 @@ select:active { var(--button-activation-overlay), var(--grey-background); } +select:disabled { + background-image: + var(--select-arrow), + var(--grey-background); +} option { /* Prevent Chrome from inheriting background-color from the is opened in Firefox: - https://bugzilla.mozilla.org/show_bug.cgi?id=1805406 */ -select:active { - /* Rotated arrow */ - background-image: url('data:image/svg+xml;utf8, \ - \ - \ - '), - var(--button-activation-overlay), - var(--grey-background); -} -select:disabled { - background-image: - var(--select-arrow), - var(--grey-background); -} -option { - /* Prevent Chrome from inheriting background-color from the is opened in Firefox: + https://bugzilla.mozilla.org/show_bug.cgi?id=1805406 */ +select:active { + /* Rotated arrow */ + background-image: url('data:image/svg+xml;utf8, \ + \ + \ + '), + var(--button-activation-overlay), + var(--grey-background); +} +select:disabled { + background-image: + var(--select-arrow), + var(--grey-background); +} +option { + /* Prevent Chrome from inheriting background-color from the is opened in Firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=1805406 */ From 7b58cb96bcb9eb9b3620054dcbbce9217a83d9d6 Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Mon, 13 Jan 2025 00:19:56 +0100 Subject: [PATCH 23/38] Add minimum width to buttons This ensures they aren't too small, even if the text label is short. --- app/styles/base.css | 1 + app/styles/input.css | 1 + 2 files changed, 2 insertions(+) diff --git a/app/styles/base.css b/app/styles/base.css index c9e60bd..aa21ea5 100644 --- a/app/styles/base.css +++ b/app/styles/base.css @@ -387,6 +387,7 @@ html { /* Control bar buttons */ #noVNC_control_bar .noVNC_button { + min-width: unset; padding: 4px 4px; vertical-align: middle; border:1px solid rgba(255, 255, 255, 0.2); diff --git a/app/styles/input.css b/app/styles/input.css index efc1804..bd543b0 100644 --- a/app/styles/input.css +++ b/app/styles/input.css @@ -176,6 +176,7 @@ input[type=submit], input::file-selector-button, button, select { + min-width: 8em; border: none; color: black; font-weight: bold; From 54e76817df2614a21469258c6a271fd5b5bb3a90 Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Mon, 13 Jan 2025 00:22:20 +0100 Subject: [PATCH 24/38] Pointer cursor on buttons & grab on sliders This makes buttons and slider stand out more. --- app/styles/input.css | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/app/styles/input.css b/app/styles/input.css index bd543b0..95ae347 100644 --- a/app/styles/input.css +++ b/app/styles/input.css @@ -182,11 +182,18 @@ select { font-weight: bold; background-color: var(--novnc-buttongrey); background-image: var(--button-activation-overlay); - + cursor: pointer; /* Disable Chrome's touch tap highlight */ -webkit-tap-highlight-color: transparent; } -input[type=image]:disabled { +input[type=button]:disabled, +input[type=color]:disabled, +input[type=image]:disabled, +input[type=reset]:disabled, +input[type=submit]:disabled, +input:disabled::file-selector-button, +button:disabled, +select:disabled { /* See Firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1798304 */ cursor: default; @@ -332,6 +339,15 @@ input[type=range] { padding: 0; background: transparent; } +input[type=range]:hover { + cursor: grab; +} +input[type=range]:active { + cursor: grabbing; +} +input[type=range]:disabled { + cursor: default; +} /* -webkit-slider.. & -moz-range.. cant be in selector lists: https://bugs.chromium.org/p/chromium/issues/detail?id=1154623 */ input[type=range]::-webkit-slider-runnable-track { From 2bc505741fc5c508db2d9896e96538c8a64e9e47 Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Mon, 13 Jan 2025 00:28:10 +0100 Subject: [PATCH 25/38] Add styling for color pickers Note that no color picker elements are currently in use, this is for completeness. --- app/styles/input.css | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/app/styles/input.css b/app/styles/input.css index 95ae347..374b93e 100644 --- a/app/styles/input.css +++ b/app/styles/input.css @@ -209,6 +209,28 @@ input[type=submit] { overflow: clip; } +/* ------- COLOR PICKERS ------- */ + +input[type=color] { + min-width: unset; + box-sizing: content-box; + width: 1.4em; + height: 1.4em; +} +input[type=color]::-webkit-color-swatch-wrapper { + padding: 0; +} +/* -webkit-color-swatch & -moz-color-swatch cant be in a selector list: + https://bugs.chromium.org/p/chromium/issues/detail?id=1154623 */ +input[type=color]::-webkit-color-swatch { + border: none; + border-radius: 6px; +} +input[type=color]::-moz-color-swatch { + border: none; + border-radius: 6px; +} + /* -- SHARED BETWEEN CHECKBOXES AND RADIOBUTTONS -- */ input[type=radio], From 331ad34d90e0992193d1b7a533fb3edbc91d9bd4 Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Mon, 13 Jan 2025 00:57:25 +0100 Subject: [PATCH 26/38] Make interface airier by increasing line-height Modern interfaces are less cramped, this makes noVNC feel more up to date. Note that this required some adjustments on noVNC_headings and noVNC_connect_button since the text now takes up more height than the images. --- app/styles/base.css | 13 +++++++++++-- app/styles/input.css | 3 ++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/app/styles/base.css b/app/styles/base.css index aa21ea5..60c092a 100644 --- a/app/styles/base.css +++ b/app/styles/base.css @@ -31,6 +31,7 @@ :root { font-family: sans-serif; + line-height: 1.6; } body { @@ -477,9 +478,12 @@ html { .noVNC_panel .noVNC_heading { background-color: var(--novnc-blue); border-radius: 6px; - padding: 5px; + padding: 5px 8px; /* Compensate for padding in image */ - padding-right: 8px; + padding-right: 11px; + display: flex; + align-items: center; + gap: 6px; color: white; font-size: 20px; white-space: nowrap; @@ -736,6 +740,11 @@ html { border-radius: 6px; background-color: var(--novnc-blue); color: white; + + display: flex; + justify-content: center; + place-items: center; + gap: 4px; } #noVNC_connect_button img { diff --git a/app/styles/input.css b/app/styles/input.css index 374b93e..731f36a 100644 --- a/app/styles/input.css +++ b/app/styles/input.css @@ -23,6 +23,7 @@ input::file-selector-button { /* Respect standard font settings */ font: inherit; + line-height: 1.6; } input:disabled, textarea:disabled, @@ -85,7 +86,7 @@ textarea { /* Make textareas show at minimum one line. This does not work when using box-sizing border-box, in which case, vertical padding and border width needs to be taken into account. */ - min-height: 1em; + min-height: 1lh; vertical-align: baseline; /* Firefox gives "text-bottom" by default */ } From 24f99e548d8135980d49124553321b995489c5bf Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Mon, 13 Jan 2025 01:18:32 +0100 Subject: [PATCH 27/38] Add styling for toggle switches These are a type of checkbox that is suitable for ON/OFF-type switches. --- app/styles/input.css | 66 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 9 deletions(-) diff --git a/app/styles/input.css b/app/styles/input.css index 731f36a..5eeac94 100644 --- a/app/styles/input.css +++ b/app/styles/input.css @@ -232,7 +232,7 @@ input[type=color]::-moz-color-swatch { border-radius: 6px; } -/* -- SHARED BETWEEN CHECKBOXES AND RADIOBUTTONS -- */ +/* -- SHARED BETWEEN CHECKBOXES, RADIOBUTTONS AND THE TOGGLE CLASS -- */ input[type=radio], input[type=checkbox] { @@ -273,7 +273,7 @@ input[type=checkbox]:focus-visible { outline-color: var(--novnc-lightblue); } input[type=checkbox]::before, -input[type=checkbox]::after, +input[type=checkbox]:not(.toggle)::after, input[type=radio]::before, input[type=radio]::after { content: ""; @@ -286,7 +286,7 @@ input[type=radio]::after { baseline of text inside them will be used instead. */ position: absolute; } -input[type=checkbox]::after, +input[type=checkbox]:not(.toggle)::after, input[type=radio]::after { width: 10px; height: 2px; @@ -296,16 +296,16 @@ input[type=radio]::after { /* ------- CHECKBOXES ------- */ -input[type=checkbox] { +input[type=checkbox]:not(.toggle) { border-radius: 4px; } -input[type=checkbox]:checked, -input[type=checkbox]:indeterminate { +input[type=checkbox]:not(.toggle):checked, +input[type=checkbox]:not(.toggle):indeterminate { background-color: var(--novnc-blue); background-image: var(--button-activation-overlay-light); background-blend-mode: overlay; } -input[type=checkbox]::before { +input[type=checkbox]:not(.toggle)::before { width: 25%; height: 55%; border-style: solid; @@ -314,10 +314,10 @@ input[type=checkbox]::before { border-radius: 1px; transform: translateY(-1px) rotate(35deg); } -input[type=checkbox]:checked::before { +input[type=checkbox]:not(.toggle):checked::before { border-color: white; } -input[type=checkbox]:indeterminate::after { +input[type=checkbox]:not(.toggle):indeterminate::after { background-color: white; } @@ -353,6 +353,54 @@ input[type=radio]:indeterminate::after { background-color: black; } +/* ------- TOGGLE SWITCHES ------- */ + +/* These are meant to be used instead of checkboxes in some cases. If all of + the following critera are true you should use a toggle switch: + + * The choice is a simple ON/OFF or ENABLE/DISABLE + * The choice doesn't give the feeling of "I agree" or "I confirm" + * There are not multiple related & grouped options + */ + +input[type=checkbox].toggle { + display: inline-block; + --checkradio-height: 18px; /* Height value used in calc, see above */ + width: 31px; + cursor: pointer; + user-select: none; + -webkit-user-select: none; + border-radius: 9px; +} +input[type=checkbox].toggle:disabled { + cursor: default; +} +input[type=checkbox].toggle:indeterminate { + background-color: var(--novnc-buttongrey); + background-image: var(--button-activation-overlay); +} +input[type=checkbox].toggle:checked { + background-color: var(--novnc-blue); + background-image: var(--button-activation-overlay-light); + background-blend-mode: overlay; +} +input[type=checkbox].toggle::before { + --circle-diameter: 10px; + --circle-offset: 4px; + width: var(--circle-diameter); + height: var(--circle-diameter); + top: var(--circle-offset); + left: var(--circle-offset); + background: white; + border-radius: 6px; +} +input[type=checkbox].toggle:checked::before { + left: calc(100% - var(--circle-offset) - var(--circle-diameter)); +} +input[type=checkbox].toggle:indeterminate::before { + left: calc(50% - var(--circle-diameter) / 2); +} + /* ------- RANGE SLIDERS ------- */ input[type=range] { From 6c1e7bc50768b07c7cf81628a45bace90f5aa23b Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Mon, 13 Jan 2025 01:19:40 +0100 Subject: [PATCH 28/38] Utilize toggle switch in settings These settings are well suited to use toggle switches. This makes these settings more approachable and user-friendly. --- vnc.html | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/vnc.html b/vnc.html index ed82b60..304b1a5 100644 --- a/vnc.html +++ b/vnc.html @@ -206,14 +206,26 @@
  • - +
  • - +

  • - +
  • @@ -244,7 +256,11 @@
    WebSocket
    • - +
    • @@ -262,7 +278,11 @@

    • - +
    • @@ -270,7 +290,11 @@

    • - +

    • From 3a5dd22603efddbed6be721a87bca2c2cff106e0 Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Mon, 13 Jan 2025 01:32:57 +0100 Subject: [PATCH 29/38] Add styling for checked options in select boxes --- app/styles/input.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/styles/input.css b/app/styles/input.css index 5eeac94..8b5f3ca 100644 --- a/app/styles/input.css +++ b/app/styles/input.css @@ -515,6 +515,9 @@ select:disabled { var(--select-arrow), var(--grey-background); } +/* Note that styling for
    -
    - - +
    + +
    @@ -383,8 +383,8 @@ -
    - +
    +
    @@ -393,7 +393,7 @@
    - +
    From 6db9dbcf905792570670f255d52b9159fb61a56b Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Tue, 14 Jan 2025 10:29:25 +0100 Subject: [PATCH 35/38] Tweak design of noVNC connect button Make the color contrast with the background and the button more rounded. The goal is to make the button stand out. --- app/styles/base.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/styles/base.css b/app/styles/base.css index 6408939..1d61bc4 100644 --- a/app/styles/base.css +++ b/app/styles/base.css @@ -737,9 +737,9 @@ html { } } #noVNC_connect_dlg div { - padding: 12px; + padding: 18px; - background-color: var(--novnc-blue); + background-color: var(--novnc-darkgrey); border-radius: 12px; text-align: center; font-size: 20px; @@ -751,7 +751,7 @@ html { padding: 6px 30px; cursor: pointer; border-color: transparent; - border-radius: 6px; + border-radius: 12px; background-color: var(--novnc-blue); color: white; From 14f9ea5880f32f2a4867006d46c8e871942c698e Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Thu, 16 Jan 2025 11:20:47 +0100 Subject: [PATCH 36/38] Fix settings panel layout on small screens Both labels and inputs protruded outside the panel on for example a phone in portrait mode. This commit fixes that by allowing wrapping and setting a max-width. Since the --input-xpadding variable is now used in two different CSS files, it was moved to constants.css. --- app/styles/base.css | 16 ++++++++++++---- app/styles/constants.css | 6 ++++++ app/styles/input.css | 4 ---- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/app/styles/base.css b/app/styles/base.css index 1d61bc4..9631570 100644 --- a/app/styles/base.css +++ b/app/styles/base.css @@ -464,16 +464,24 @@ html { white-space: nowrap; margin: 5px; } +@media (max-width: 540px) { + /* Allow wrapping on small screens */ + .noVNC_panel label { + white-space: unset; + } +} .noVNC_panel li { margin: 5px; } -.noVNC_panel label > button, -.noVNC_panel label > select, -.noVNC_panel label > textarea, -.noVNC_panel label > input:not([type=checkbox]):not([type=radio]) { +.noVNC_panel button, +.noVNC_panel select, +.noVNC_panel textarea, +.noVNC_panel input:not([type=checkbox]):not([type=radio]) { margin-left: 6px; + /* Prevent inputs in panels from being too wide */ + max-width: calc(100% - 6px - var(--input-xpadding) * 2); } .noVNC_panel .noVNC_heading { diff --git a/app/styles/constants.css b/app/styles/constants.css index daf3961..1123a3e 100644 --- a/app/styles/constants.css +++ b/app/styles/constants.css @@ -22,3 +22,9 @@ --novnc-green: rgb(0, 128, 0); --novnc-yellow: rgb(255, 255, 0); } + +/* ------ MISC PROPERTIES ------ */ + +:root { + --input-xpadding: 1em; +} diff --git a/app/styles/input.css b/app/styles/input.css index 1be9597..8273d70 100644 --- a/app/styles/input.css +++ b/app/styles/input.css @@ -7,10 +7,6 @@ /* ------- SHARED BETWEEN INPUT ELEMENTS -------- */ -:root { - --input-xpadding: 1em; -} - input, textarea, button, From 237a34dfb39d8937e4c502618f3749e81f64f72a Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Thu, 23 Jan 2025 13:16:14 +0100 Subject: [PATCH 37/38] Add exceptions for CSS validator false positives Some new CSS incorrectly give errors from validator.w3.org. Issues were opened in that repo, so hopefully we can remove these exceptions soon. I searched for alternative validators, but couldn't find a different one that had a simple API like this one. In order to reliably detect & handle these exceptions we unfortunately need to make the validator output parsing quite a bit more complicated. --- utils/validate | 57 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 5 deletions(-) diff --git a/utils/validate b/utils/validate index a6b5507..3f5cb87 100755 --- a/utils/validate +++ b/utils/validate @@ -28,16 +28,63 @@ for fn in "$@"; do curl --silent \ --header "Content-Type: ${type}; charset=utf-8" \ --data-binary @${fn} \ - https://validator.w3.org/nu/?out=text > $OUT - cat $OUT - echo + "https://validator.w3.org/nu/?out=gnu&level=error&asciiquotes=yes" \ + > $OUT # We don't fail the check for warnings as some warnings are # not relevant for us, and we don't currently have a way to # ignore just those - if grep -q -s -E "^Error:" $OUT; then + while read -r line; do + echo + + line_info=$(echo $line | cut -d ":" -f 2) + start_info=$(echo $line_info | cut -d "-" -f 1) + end_info=$(echo $line_info | cut -d "-" -f 2) + + line_start=$(echo $start_info | cut -d "." -f 1) + col_start=$(echo $start_info | cut -d "." -f 2) + + line_end=$(echo $end_info | cut -d "." -f 1) + col_end=$(echo $end_info | cut -d "." -f 2) + + error=$(echo $line | cut -d ":" -f 4-) + + case $error in + *"\"scrollbar-gutter\": Property \"scrollbar-gutter\" doesn't exist.") + # FIXME: https://github.com/validator/validator/issues/1788 + echo "Ignoring below error on line ${line_start}," \ + "the scrollbar-gutter property actually exist and is widely" \ + "supported:" + echo $error + continue + ;; + *"\"clip-path\": \"path("*) + # FIXME: https://github.com/validator/validator/issues/1786 + echo "Ignoring below error on line ${line_start}," \ + "the path() function is valid for clip-path and is" \ + "widely supported:" + echo $error + continue + ;; + *"Parse Error.") + # FIXME: https://github.com/validator/validator/issues/1786 + lineofselector=$(grep -n "@supports selector(" $fn | cut -d ":" -f 1) + linediff=$((lineofselector-line_start)) + # Only ignore if parse error is within 50 lines of "selector()" + if [ ${linediff#-} -lt 50 ]; then + echo "Ignoring below error on line ${line_start}," \ + "the @supports selector() function should not give a parse" \ + "error:" + echo $error + continue + fi + ;; + esac + echo "ERROR between line ${line_start} (col ${col_start})" \ + "and line ${line_end} (col ${col_end}):" + echo $error RET=1 - fi + done < "$OUT" done rm $OUT From 24835bdda4ff705c38f64616501635a1b6ba81ec Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Thu, 23 Jan 2025 14:22:32 +0100 Subject: [PATCH 38/38] Make the background of expanded settings lighter A very slight change to the background color, to make the contrast better with the light-grey input elements. --- app/styles/base.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/styles/base.css b/app/styles/base.css index 9631570..87bfb45 100644 --- a/app/styles/base.css +++ b/app/styles/base.css @@ -535,7 +535,7 @@ html { margin: 5px; margin-left: 10px; padding: 5px; - background: rgba(0, 0, 0, 0.05); + background: rgba(0, 0, 0, 0.04); border-radius: 6px; } .noVNC_expander:not(.noVNC_open) ~ * {