Implemented Slider

pull/7319/merge
Cagatay Civici 2025-03-01 17:43:15 +03:00
parent b1466fd7cd
commit fb5fa733fc
13 changed files with 317 additions and 10 deletions

View File

@ -26,6 +26,10 @@
"name": "InputText",
"to": "/inputtext"
},
{
"name": "Slider",
"to": "/slider"
},
{
"name": "Textarea",
"to": "/textarea"

View File

@ -0,0 +1,31 @@
<template>
<DocSectionText v-bind="$attrs">
<p>Slider is used with the <i>v-model</i> property for two-way value binding.</p>
</DocSectionText>
<div class="card flex justify-center">
<PlexSlider v-model="value" class="w-56" />
</div>
<DocSectionCode :code="code" hideToggleCode hideStackBlitz />
</template>
<script setup>
import PlexSlider from '@/plex/slider';
import { ref } from 'vue';
const value = ref(null);
const code = ref(`
<template>
<div class="card flex justify-center">
<PlexSlider v-model="value" class="w-56" />
</div>
</template>
<script setup>
import PlexSlider from '@/plex/slider';
import { ref } from 'vue';
const value = ref(null);
<\/script>
`);
</script>

View File

@ -0,0 +1,31 @@
<template>
<DocSectionText v-bind="$attrs">
<p>Image filter implementation using multiple sliders.</p>
</DocSectionText>
<div class="card flex justify-center">
<PlexSlider v-model="value" class="w-56" />
</div>
<DocSectionCode :code="code" hideToggleCode hideStackBlitz />
</template>
<script setup>
import PlexSlider from '@/plex/slider';
import { ref } from 'vue';
const value = ref(null);
const code = ref(`
<template>
<div class="card flex justify-center">
<PlexSlider v-model="value" class="w-56" />
</div>
</template>
<script setup>
import PlexSlider from '@/plex/slider';
import { ref } from 'vue';
const value = ref(null);
<\/script>
`);
</script>

View File

@ -0,0 +1,16 @@
<template>
<DocSectionText v-bind="$attrs" />
<DocSectionCode :code="code" lang="script" />
</template>
<script>
export default {
data() {
return {
code: `
import PlexSlider from '@/plex/slider';
`
};
}
};
</script>

View File

@ -0,0 +1,37 @@
<template>
<DocSectionText v-bind="$attrs">
<p>Slider is connected to an input field using two-way binding.</p>
</DocSectionText>
<div class="card flex justify-center">
<div class="w-56">
<PlexInputText v-model.number="value" class="w-full mb-4" />
<PlexSlider v-model="value" class="w-full" />
</div>
</div>
<DocSectionCode :code="code" />
</template>
<script setup>
import PlexInputText from '@/plex/inputtext';
import PlexSlider from '@/plex/slider';
import { ref } from 'vue';
const value = ref(50);
const code = ref(`
<div class="card flex justify-center">
<div class="w-56">
<PlexInputText v-model.number="value" class="w-full mb-4" />
<PlexSlider v-model="value" class="w-full" />
</div>
</div>
<script setup>
import PlexInputText from '@/plex/inputtext';
import PlexSlider from '@/plex/slider';
import { ref } from 'vue';
const value = ref(50);
<\/script>
`);
</script>

View File

@ -0,0 +1,31 @@
<template>
<DocSectionText v-bind="$attrs">
<p>When <i>range</i> property is present, slider provides two handles to define two values. In range mode, value should be an array instead of a single value.</p>
</DocSectionText>
<div class="card flex justify-center">
<PlexSlider v-model="value" range class="w-56" />
</div>
<DocSectionCode :code="code" />
</template>
<script setup>
import PlexSlider from '@/plex/slider';
import { ref } from 'vue';
const value = ref([20, 80]);
const code = ref(`
<template>
<div class="card flex justify-center">
<PlexSlider v-model="value" range class="w-56" />
</div>
</template>
<script setup>
import PlexSlider from '@/plex/slider';
import { ref } from 'vue';
const value = ref([20, 80]);
<\/script>
`);
</script>

View File

@ -0,0 +1,31 @@
<template>
<DocSectionText v-bind="$attrs">
<p>Size of each movement is defined with the <i>step</i> property.</p>
</DocSectionText>
<div class="card flex justify-center">
<PlexSlider v-model="value" :step="20" class="w-56" />
</div>
<DocSectionCode :code="code" />
</template>
<script setup>
import PlexSlider from '@/plex/slider';
import { ref } from 'vue';
const value = ref(20);
const code = ref(`
<template>
<div class="card flex justify-center">
<PlexSlider v-model="value" :step="20" class="w-56" />
</div>
</template>
<script setup>
import PlexSlider from '@/plex/slider';
import { ref } from 'vue';
const value = ref(20);
<\/script>
`);
</script>

View File

@ -0,0 +1,31 @@
<template>
<DocSectionText v-bind="$attrs">
<p>Default layout of slider is <i>horizontal</i>, use <i>orientation</i> property for the alternative <i>vertical</i> mode.</p>
</DocSectionText>
<div class="card flex justify-center">
<PlexSlider v-model="value" orientation="vertical" class="h-56" />
</div>
<DocSectionCode :code="code" hideToggleCode hideStackBlitz />
</template>
<script setup>
import PlexSlider from '@/plex/slider';
import { ref } from 'vue';
const value = ref(50);
const code = ref(`
<template>
<div class="card flex justify-center">
<PlexSlider v-model="value" orientation="vertical" class="h-56" />
</div>
</template>
<script setup>
import PlexSlider from '@/plex/slider';
import { ref } from 'vue';
const value = ref(50);
<\/script>
`);
</script>

View File

@ -0,0 +1,52 @@
<template>
<DocComponent title="Vue Slider Component" header="Slider" description="Slider is a component to provide input with a drag handle." :componentDocs="docs" />
</template>
<script setup>
import BasicDoc from '@/doc/slider/BasicDoc.vue';
/*import FilterDoc from '@/doc/slider/FilterDoc.vue';*/
import ImportDoc from '@/doc/slider/ImportDoc.vue';
import InputDoc from '@/doc/slider/InputDoc.vue';
import RangeDoc from '@/doc/slider/RangeDoc.vue';
import StepDoc from '@/doc/slider/StepDoc.vue';
import VerticalDoc from '@/doc/slider/VerticalDoc.vue';
import { ref } from 'vue';
const docs = ref([
{
id: 'import',
label: 'Import',
component: ImportDoc
},
{
id: 'basic',
label: 'Basic',
component: BasicDoc
},
{
id: 'input',
label: 'Input',
component: InputDoc
},
{
id: 'step',
label: 'Step',
component: StepDoc
},
{
id: 'range',
label: 'Range',
component: RangeDoc
},
/*{
id: 'filter',
label: 'Filter',
component: FilterDoc
},*/
{
id: 'vertical',
label: 'Vertical',
component: VerticalDoc
}
]);
</script>

View File

@ -1,5 +1,5 @@
<template>
<DocComponent title="Vue Textarea Component" header="InputText" description="Textarea adds styling and auto-resize functionality to standard textarea element." :componentDocs="docs" />
<DocComponent title="Vue Textarea Component" header="Textarea" description="Textarea adds styling and auto-resize functionality to standard textarea element." :componentDocs="docs" />
</template>
<script setup>

View File

@ -0,0 +1,31 @@
<template>
<Slider unstyled :pt="theme" />
</template>
<script setup>
import Slider from 'primevue/slider';
import { ref } from 'vue';
const handleCommon = `cursor-grab touch-none flex items-center justify-center h-[20px] w-[20px]
bg-surface-200 dark:bg-surface-700 rounded-full
transition-colors duration-200
focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary
before:w-[16px] before:h-[16px] before:block before:rounded-full
before:bg-surface-0 dark:before:bg-surface-950
before:shadow-[0px_0.5px_0px_0px_rgba(0,0,0,0.08),0px_1px_1px_0px_rgba(0,0,0,0.14)]
before:transition-colors before:duration-200
p-horizontal:top-1/2 p-horizontal:-mt-[10px] p-horizontal:-ms-[10px]
p-vertical:start-1/2 p-vertical:-mb-[10px] p-vertical:-ms-[10px]`;
const theme = ref({
root: `relative bg-surface-200 dark:bg-surface-700 rounded-sm
p-horizontal:h-[3px]
p-vertical:min-h-[100px] p-vertical:w-[3px]`,
range: `block bg-primary rounded-sm
p-horizontal:top-0 p-horizontal:start-0 p-horizontal:h-full
p-vertical:bottom-0 p-vertical:start-0 p-vertical:w-full`,
handle: handleCommon,
startHandler: handleCommon,
endHandler: handleCommon
});
</script>

View File

@ -5,13 +5,16 @@ import plugin from 'tailwindcss/plugin';
export default {
darkMode: ['selector', '[class~="p-dark"]'],
content: ['./components/**/*.{js,vue,ts}', './doc/**/*.{js,vue,ts}', './plex/**/*.{js,vue,ts}', './layouts/**/*.vue', './pages/**/*.vue', './plugins/**/*.{js,ts}', './nuxt.config.{js,ts}', './app.vue', './error.vue'],
plugins: [PrimeUI,
plugin(function({ addVariant }) {
addVariant('p-invalid', '&[data-p~="invalid"]')
addVariant('p-small', '&[data-p~="small"]')
addVariant('p-large', '&[data-p~="large"]')
addVariant('p-fluid', '&[data-p~="fluid"]')
addVariant('p-filled', '&[data-p~="filled"]')
plugins: [
PrimeUI,
plugin(function ({ addVariant }) {
addVariant('p-invalid', '&[data-p~="invalid"]');
addVariant('p-small', '&[data-p~="small"]');
addVariant('p-large', '&[data-p~="large"]');
addVariant('p-fluid', '&[data-p~="fluid"]');
addVariant('p-filled', '&[data-p~="filled"]');
addVariant('p-horizontal', '&[data-p~="horizontal"]');
addVariant('p-vertical', '&[data-p~="vertical"]');
})
],
theme: {

View File

@ -1,6 +1,6 @@
<template>
<div :class="cx('root')" @click="onBarClick" v-bind="ptmi('root')" :data-p-sliding="false">
<span :class="cx('range')" :style="[sx('range'), rangeStyle()]" v-bind="ptm('range')"></span>
<div :class="cx('root')" @click="onBarClick" v-bind="ptmi('root')" :data-p-sliding="false" :data-p="dataP">
<span :class="cx('range')" :style="[sx('range'), rangeStyle()]" v-bind="ptm('range')" :data-p="dataP"></span>
<span
v-if="!range"
:class="cx('handle')"
@ -20,6 +20,7 @@
:aria-label="ariaLabel"
:aria-orientation="orientation"
v-bind="ptm('handle')"
:data-p="dataP"
></span>
<span
v-if="range"
@ -40,6 +41,7 @@
:aria-label="ariaLabel"
:aria-orientation="orientation"
v-bind="ptm('startHandler')"
:data-p="dataP"
></span>
<span
v-if="range"
@ -60,11 +62,13 @@
:aria-label="ariaLabel"
:aria-orientation="orientation"
v-bind="ptm('endHandler')"
:data-p="dataP"
></span>
</div>
</template>
<script>
import { cn } from '@primeuix/utils/classnames';
import { getAttribute, getWindowScrollLeft, getWindowScrollTop, isRTL } from '@primeuix/utils/dom';
import BaseSlider from './BaseSlider.vue';
@ -359,6 +363,11 @@ export default {
if (this.value[1] > this.max) return 100;
else return ((this.value[1] - this.min) * 100) / (this.max - this.min);
} else return 100;
},
dataP() {
return cn({
[this.orientation]: this.orientation
});
}
}
};