refactor(ui): improve slider style

This commit is contained in:
upsiflu 2025-02-04 14:54:09 +01:00
parent 337373ff75
commit 0b4d5b3acd
2 changed files with 66 additions and 15 deletions

View File

@ -3,6 +3,7 @@ import { ref, computed, onMounted } from 'vue'
import Layout from "~/components/ui/Layout.vue"
import Spacer from "~/components/ui/Spacer.vue"
import Markdown from "~/components/ui/Markdown.vue"
const props = defineProps<{
label?: string,
@ -48,7 +49,7 @@ onMounted(() => {
{{ label }}
</label>
<!-- Model indicator -->
<!-- List of options -->
<Layout flex no-gap>
<button v-for="key in keys" :class="[$style.key, {[$style.current]: key===model}]"
@ -62,19 +63,23 @@ onMounted(() => {
<!-- Slider -->
<input ref="input" type="range"
style="width: var(--slider-width);"
:max="keys.length - 1"
v-model="index"
/>
<span style="position: relative;">
<input ref="input" type="range"
style="width: var(--slider-width); opacity: .001;"
:max="keys.length - 1"
v-model="index" />
<div :class="$style.range" />
<div :class="$style.pin" />
</span>
<Spacer size-8/>
<!-- Description of current option -->
<span style="position: relative;">
<span style="display: inline-flex; margin-right: -100%; width: 100%; visibility: hidden;" >
<span v-for="key in keys" :class="$style.description" :style="`margin-right: -20%; --current-step: 0; color: magenta;`">{{ options[key] }}</span>
</span>
<span style="position: absolute;" :class="$style.description">{{ options[model] }}</span>
<span style="display: inline-flex; margin-right: -100%; width: 100%; visibility: hidden;" >
<span v-for="key in keys" :class="$style.description" :style="`margin-right: -20%; --current-step: 0; color: magenta;`"><Markdown :md="options[key]" /></span>
</span>
<span style="position: absolute;" :class="$style.description"><Markdown :md="options[model]" /></span>
</span>
</Layout>
</template>
@ -103,5 +108,37 @@ onMounted(() => {
--inset: calc(var(--step-size) * var(--current-step));
margin-left: var(--inset);
margin-right: calc(0px - var(--inset));
p {
margin: 0;
line-height: 1.5em;
}
}
// Fake slider
.range {
width: calc(var(--step-size) * var(--current-step));
border-bottom: 2px solid currentcolor;
position: absolute;
top: 11px;
transition: all .1s;
pointer-events: none;
}
input:focus~.range {
// focused style
}
.pin {
border-radius: 8px;
width: 16px;
height: 16px;
left: calc(var(--step-size) * var(--current-step));
background: currentcolor;
position: absolute;
top: 4px;
transition: all .1s;
pointer-events: none;
}
input:focus~.pin {
background-color: var(--focus-ring-color);
outline: 2px solid currentcolor;
}
</style>

View File

@ -1,6 +1,7 @@
<script setup lang="ts">
import { ref } from 'vue'
import Spacer from "~/components/ui/Spacer.vue"
import Slider from '~/components/ui/Slider.vue'
const options = {
@ -9,7 +10,7 @@ const options = {
everyone: "Everyone can find and edit this"
} as const
const option = ref<keyof typeof options>('me')
const option = ref<keyof typeof options>('pod')
</script>
```ts
@ -18,9 +19,10 @@ import Slider from "~/components/ui/Slider.vue";
# Slider
Let a user select a value along a gradient.
Let a user select a value along a line.
The model (required) is the current value.
For each option, provide a description. Markdown is supported.
Select a key from the `options` by setting `v-model`
```ts
const options = {
@ -33,10 +35,21 @@ const option = ref<keyof typeof options>("me");
```
```vue-html
<Slider :options="options" v-model="option" label="Privacy" />
<Slider :options="options" v-model="option" label="Privacy level" />
```
<Slider :options="options" v-model="option" label="Privacy" />
<Spacer />
<Slider :options="options" v-model="option" label="Privacy level" />
## Add a label
You can either specify the `label` prop or add custom Html into the `#label` slot.
## Autofocus
Add the prop `autofocus` to focus the slider as soon as it renders. Make sure to only autofocus one element per page.
---
Functionality:
@ -55,5 +68,6 @@ Design:
- A pin (same as in the toggle component)
- a range (very faint)
- Ticks
- Constant dimensions, fitting the largest text box
- Not to be confused with a pearls navigation patterns (list of dots; indicates temporal range)