From 857f52a1c216a353e3c9b735500a8052ccc4fe56 Mon Sep 17 00:00:00 2001 From: Juergen Fuhrmann Date: Sun, 24 Oct 2021 21:38:15 +0200 Subject: [PATCH] Slider styling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The idea comes from an example by Márk Munkácsi, see https://dev.to/munkacsimark/styled-range-input-a-way-out-of-range-input-nightmare-jeo It was public on Codepen, so it is MIT licensed. --- assets/slider.css | 110 ++++++++++++++++++++++++++++++++++++++++++++++ assets/slider.js | 53 ++++++++++++++++++++++ src/Builtins.jl | 11 ++++- 3 files changed, 172 insertions(+), 2 deletions(-) create mode 100644 assets/slider.css create mode 100644 assets/slider.js diff --git a/assets/slider.css b/assets/slider.css new file mode 100644 index 00000000..2f9433e2 --- /dev/null +++ b/assets/slider.css @@ -0,0 +1,110 @@ +/* + Slider styling css after Márk Munkácsi. + This was public on codepen, so it is MIT: https://blog.codepen.io/documentation/licensing/ + See https://dev.to/munkacsimark/styled-range-input-a-way-out-of-range-input-nightmare-jeo , + also for explanations. +*/ + +/* + These variables configures the appearance of the slider. + + Two modifications wrt. to the orginal (citation above): + + - colors modifid in order to work better with white background. + - added variable `--width` +*/ +input[type="range"] { + --thumbSize: 15px; + --trackSize: 8px; + --thumbBg: #ddd; + --trackBg: #ccc; + --progressBg: #888; + --width: 13%; + /* webkit progress workaround */ + --webkitProgressPercent: 0%; +} + +input[type="range"] { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + height: var(--thumbSize); + width: var(--width); + margin: 0; + padding: 0; +} + +input[type="range"]:focus { + outline: none; +} + +/* Thumb */ +input[type="range"]::-webkit-slider-thumb { + -webkit-appearance: none; + appearance: none; + width: var(--thumbSize); + height: var(--thumbSize); + background-color: var(--thumbBg); + border-radius: calc(var(--thumbSize) / 2); + border: none; + box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2); + margin-top: calc(((var(--thumbSize) - var(--trackSize)) / 2) * -1); + cursor: pointer; +} +input[type="range"]::-moz-range-thumb { + -moz-appearance: none; + appearance: none; + width: var(--thumbSize); + height: var(--thumbSize); + background-color: var(--thumbBg); + border-radius: calc(var(--thumbSize) / 2); + border: none; + box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2); + margin-top: calc(((var(--thumbSize) - var(--trackSize)) / 2) * -1); + cursor: pointer; +} +input[type="range"]::-ms-thumb { + -ms-appearance: none; + appearance: none; + width: var(--thumbSize); + height: var(--thumbSize); + background-color: var(--thumbBg); + border-radius: calc(var(--thumbSize) / 2); + border: none; + box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2); + margin-top: calc(((var(--thumbSize) - var(--trackSize)) / 2) * -1); + cursor: pointer; +} + +/* Track */ +input[type="range"]::-webkit-slider-runnable-track { + height: var(--trackSize); + background-image: linear-gradient( + 90deg, + var(--progressBg) var(--webkitProgressPercent), + var(--trackBg) var(--webkitProgressPercent) + ); + border-radius: calc(var(--trackSize) / 2); +} +input[type="range"]::-moz-range-track { + height: var(--trackSize); + background-color: var(--trackBg); + border-radius: calc(var(--trackSize) / 2); +} +input[type="range"]::-ms-track { + height: var(--trackSize); + background-color: var(--trackBg); + border-radius: calc(var(--trackSize) / 2); +} + +/* Progress */ +input[type="range"]::-moz-range-progress { + height: var(--trackSize); + background-color: var(--progressBg); + border-radius: calc(var(--trackSize) / 2) 0 0 calc(var(--trackSize) / 2); +} +input[type="range"]::-ms-fill-lower { + height: var(--trackSize); + background-color: var(--progressBg); + border-radius: calc(var(--trackSize) / 2) 0 0 calc(var(--trackSize) / 2); +} diff --git a/assets/slider.js b/assets/slider.js new file mode 100644 index 00000000..65314ced --- /dev/null +++ b/assets/slider.js @@ -0,0 +1,53 @@ +/* + Slider styling javascript after Márk Munkácsi. + This was public on codepen, so it is MIT: https://blog.codepen.io/documentation/licensing/ + See https://dev.to/munkacsimark/styled-range-input-a-way-out-of-range-input-nightmare-jeo , + also for explanations. + + + The javascript is used to set the progress bar. +*/ + +// Unmodified from the original (see above) +const handleInput = (inputElement) => { + let isChanging = false; + + const setCSSProperty = () => { + const percent = + ((inputElement.value - inputElement.min) / + (inputElement.max - inputElement.min)) * + 100; + // Here comes the magic 🦄🌈 + inputElement.style.setProperty("--webkitProgressPercent", `${percent}%`); + } + + // Set event listeners + const handleMove = () => { + if (!isChanging) return; + setCSSProperty(); + }; + const handleUpAndLeave = () => isChanging = false; + const handleDown = () => isChanging = true; + + inputElement.addEventListener("mousemove", handleMove); + inputElement.addEventListener("mousedown", handleDown); + inputElement.addEventListener("mouseup", handleUpAndLeave); + inputElement.addEventListener("mouseleave", handleUpAndLeave); + inputElement.addEventListener("click", setCSSProperty); + + // Init input + setCSSProperty(); +} + + +// This was the original code which would affect all sliders at once: + +// const inputElements = document.querySelectorAll('[type="range"]'); +// inputElements.forEach(handleInput) + + +// Modification for handle only the currenly created slider in pluto. +// need to go two elements back because of the follwing +// directly the +const slider = (currentScript ?? this.currentScript).previousElementSibling.previousElementSibling +handleInput(slider) diff --git a/src/Builtins.jl b/src/Builtins.jl index 168f7f29..29247621 100644 --- a/src/Builtins.jl +++ b/src/Builtins.jl @@ -75,6 +75,9 @@ begin """ Slider(range::AbstractRange; default=missing, show_value=false) = Slider(range, (default === missing) ? first(range) : default, show_value) + const slider_js = HypertextLiteral.JavaScript(read(joinpath(@__DIR__, "..", "assets", "slider.js"), String)) + const slider_css = read(joinpath(@__DIR__, "..", "assets", "slider.css"), String) + function Base.show(io::IO, m::MIME"text/html", slider::Slider) show(io, m, @htl(""" - $( slider.show_value ? @htl("$(slider.default)") : nothing ) - + + """)) end