mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-12-11 14:45:59 +08:00
Add design page and refactored dropdown [SCI-9680]
This commit is contained in:
parent
8f862f3290
commit
c09ce12ddc
9 changed files with 596 additions and 12 deletions
|
|
@ -51,6 +51,30 @@ $sn-icon-check: "\e95f";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sn-checkbox-icon {
|
||||||
|
background-position: center center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: contain;
|
||||||
|
height: 1rem;
|
||||||
|
width: 1rem;
|
||||||
|
|
||||||
|
&.unchecked {
|
||||||
|
background-image: asset-url("checkbox/default.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
&.checked {
|
||||||
|
background-image: asset-url("checkbox/checked.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
background-image: asset-url("checkbox/disabled.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
&.indeterminate {
|
||||||
|
background-image: asset-url("checkbox/indeterminate.svg");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@mixin font-h1 {
|
@mixin font-h1 {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
|
|
||||||
19
app/controllers/design_elements_controller.rb
Normal file
19
app/controllers/design_elements_controller.rb
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
class DesignElementsController < ApplicationController
|
||||||
|
def index
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_select
|
||||||
|
render json: { data: [
|
||||||
|
['1', 'One'],
|
||||||
|
['2', 'Two'],
|
||||||
|
['3', 'Three'],
|
||||||
|
['4', 'Four'],
|
||||||
|
['5', 'Five'],
|
||||||
|
['6', 'Six'],
|
||||||
|
['7', 'Seven'],
|
||||||
|
['8', 'Eight'],
|
||||||
|
['9', 'Nine'],
|
||||||
|
['10', 'Ten']
|
||||||
|
].select { |item| item[1].downcase.include?(params[:query].downcase) } }
|
||||||
|
end
|
||||||
|
end
|
||||||
45
app/javascript/packs/vue/design_system/select.js
Normal file
45
app/javascript/packs/vue/design_system/select.js
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
import { createApp } from 'vue/dist/vue.esm-bundler.js';
|
||||||
|
import SelectDropdown from '../../../vue/shared/select_dropdown.vue';
|
||||||
|
import PerfectScrollbar from 'vue3-perfect-scrollbar';
|
||||||
|
import { mountWithTurbolinks } from '../helpers/turbolinks.js';
|
||||||
|
|
||||||
|
const app = createApp({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
size: 'md',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
simpleOptions() {
|
||||||
|
return [
|
||||||
|
['1', 'One', { icon: 'sn-icon-edit' }],
|
||||||
|
['2', 'Two', { icon: 'sn-icon-drag' }],
|
||||||
|
['3', 'Three', { icon: 'sn-icon-delete' }],
|
||||||
|
['4', 'Four', { icon: 'sn-icon-visibility-show' }],
|
||||||
|
['5', 'Five', { icon: 'sn-icon-edit' }],
|
||||||
|
['6', 'Six', { icon: 'sn-icon-locked-task' }],
|
||||||
|
['7', 'Seven', { icon: 'sn-icon-drag' }],
|
||||||
|
['8', 'Eight', { icon: 'sn-icon-delete' }],
|
||||||
|
['9', 'Nine', { icon: 'sn-icon-edit' }],
|
||||||
|
['10', 'Ten', { icon: 'sn-icon-close' }],
|
||||||
|
];
|
||||||
|
},
|
||||||
|
longOptions() {
|
||||||
|
return [
|
||||||
|
['1', 'Very long long long option and label to test responsivness'],
|
||||||
|
['2', 'Two'],
|
||||||
|
['3', 'Three'],
|
||||||
|
['4', 'Four'],
|
||||||
|
]
|
||||||
|
},
|
||||||
|
renderer() {
|
||||||
|
return (option) => {
|
||||||
|
return `<span class="flex items-center gap-2"><i class="sn-icon ${option[2].icon}"></i> ${option[1]}</span>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
app.component('SelectDropdown', SelectDropdown);
|
||||||
|
app.config.globalProperties.i18n = window.I18n;
|
||||||
|
app.use(PerfectScrollbar);
|
||||||
|
mountWithTurbolinks(app, '#selects');
|
||||||
|
|
@ -5,14 +5,11 @@
|
||||||
<i class="sn-icon sn-icon-search"></i>
|
<i class="sn-icon sn-icon-search"></i>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="currentTeam" class="w-64">
|
<div v-if="currentTeam" class="w-64">
|
||||||
<Select
|
<SelectDropdown
|
||||||
:value="currentTeam"
|
:value="currentTeam"
|
||||||
:options="teams"
|
:options="teams"
|
||||||
:placeholder="'test'"
|
|
||||||
:noOptionsPlaceholder="'test'"
|
|
||||||
v-bind:disabled="false"
|
|
||||||
@change="switchTeam"
|
@change="switchTeam"
|
||||||
></Select>
|
></SelectDropdown>
|
||||||
</div>
|
</div>
|
||||||
<MenuDropdown
|
<MenuDropdown
|
||||||
class="ml-auto"
|
class="ml-auto"
|
||||||
|
|
@ -63,7 +60,7 @@
|
||||||
<script>
|
<script>
|
||||||
import NotificationsFlyout from './notifications/notifications_flyout.vue';
|
import NotificationsFlyout from './notifications/notifications_flyout.vue';
|
||||||
import DropdownSelector from '../shared/dropdown_selector.vue';
|
import DropdownSelector from '../shared/dropdown_selector.vue';
|
||||||
import Select from "../shared/select.vue";
|
import SelectDropdown from "../shared/select_dropdown.vue";
|
||||||
import MenuDropdown from '../shared/menu_dropdown.vue';
|
import MenuDropdown from '../shared/menu_dropdown.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
@ -71,8 +68,8 @@
|
||||||
components: {
|
components: {
|
||||||
DropdownSelector,
|
DropdownSelector,
|
||||||
NotificationsFlyout,
|
NotificationsFlyout,
|
||||||
Select,
|
MenuDropdown,
|
||||||
MenuDropdown
|
SelectDropdown
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
url: String,
|
url: String,
|
||||||
|
|
|
||||||
|
|
@ -45,11 +45,11 @@
|
||||||
<div class="flex items-center gap-4">
|
<div class="flex items-center gap-4">
|
||||||
{{ i18n.t('datatable.show') }}
|
{{ i18n.t('datatable.show') }}
|
||||||
<div class="w-36">
|
<div class="w-36">
|
||||||
<Select
|
<SelectDropdown
|
||||||
:value="perPage"
|
:value="perPage"
|
||||||
:options="perPageOptions"
|
:options="perPageOptions"
|
||||||
@change="setPerPage"
|
@change="setPerPage"
|
||||||
></Select>
|
></SelectDropdown>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -59,7 +59,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { AgGridVue } from "ag-grid-vue3";
|
import { AgGridVue } from "ag-grid-vue3";
|
||||||
import axios from '../../../packs/custom_axios.js';
|
import axios from '../../../packs/custom_axios.js';
|
||||||
import Select from '../select.vue';
|
import SelectDropdown from '../select_dropdown.vue';
|
||||||
import PerfectScrollbar from 'vue3-perfect-scrollbar';
|
import PerfectScrollbar from 'vue3-perfect-scrollbar';
|
||||||
import Pagination from './pagination.vue';
|
import Pagination from './pagination.vue';
|
||||||
import CustomHeader from './tableHeader';
|
import CustomHeader from './tableHeader';
|
||||||
|
|
@ -137,7 +137,7 @@ export default {
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
AgGridVue,
|
AgGridVue,
|
||||||
Select,
|
SelectDropdown,
|
||||||
PerfectScrollbar,
|
PerfectScrollbar,
|
||||||
Pagination,
|
Pagination,
|
||||||
agColumnHeader: CustomHeader,
|
agColumnHeader: CustomHeader,
|
||||||
|
|
|
||||||
272
app/javascript/vue/shared/select_dropdown.vue
Normal file
272
app/javascript/vue/shared/select_dropdown.vue
Normal file
|
|
@ -0,0 +1,272 @@
|
||||||
|
<template>
|
||||||
|
<div v-click-outside="close" class="w-full">
|
||||||
|
<div
|
||||||
|
ref="field"
|
||||||
|
class="px-3 border border-solid border-sn-light-grey rounded flex items-center cursor-pointer"
|
||||||
|
@click="open"
|
||||||
|
:class="[sizeClass, {
|
||||||
|
'border-sn-blue': isOpen,
|
||||||
|
'bg-sn-sleepy-grey': disabled
|
||||||
|
}]"
|
||||||
|
>
|
||||||
|
<template v-if="!isOpen || !searchable">
|
||||||
|
<div class="truncate" v-if="labelRenderer && label" v-html="label"></div>
|
||||||
|
<div class="truncate" v-else-if="label">{{ label }}</div>
|
||||||
|
<div class="text-sn-grey truncate" v-else>{{ placeholder }}</div>
|
||||||
|
</template>
|
||||||
|
<input type="text"
|
||||||
|
ref="search"
|
||||||
|
v-else
|
||||||
|
v-model="query"
|
||||||
|
:placeholder="label || placeholder"
|
||||||
|
class="w-full border-0 outline-none pl-0 placeholder:text-sn-grey" />
|
||||||
|
<i v-if="canClear" @click="clear" class="sn-icon ml-auto sn-icon-close"></i>
|
||||||
|
<i v-else class="sn-icon ml-auto" :class="{ 'sn-icon-down': !isOpen, 'sn-icon-up': isOpen, 'text-sn-grey': disabled}"></i>
|
||||||
|
</div>
|
||||||
|
<div v-if="isOpen" ref="flyout" class="bg-white sn-shadow-menu-sm rounded w-full fixed z-50">
|
||||||
|
<div v-if="multiple && withCheckboxes" class="p-2.5 pb-0">
|
||||||
|
<div @click="selectAll" :class="sizeClass" class="border-transparent border-solid border-b-sn-light-grey py-1.5 px-3 cursor-pointer flex items-center gap-2 shrink-0">
|
||||||
|
<div class="sn-checkbox-icon"
|
||||||
|
:class="selectAllState"
|
||||||
|
></div>
|
||||||
|
{{ i18n.t('general.select_all') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<perfect-scrollbar class="p-2.5 flex flex-col max-h-80 relative" :class="{ 'pt-0': withCheckboxes }">
|
||||||
|
<template v-for="option in filteredOptions" :key="option[0]">
|
||||||
|
<div
|
||||||
|
@click="setValue(option[0])"
|
||||||
|
class="py-1.5 px-3 rounded cursor-pointer flex items-center gap-2 shrink-0"
|
||||||
|
:class="[sizeClass, {'!bg-sn-super-light-blue': valueSelected(option[0])}]"
|
||||||
|
>
|
||||||
|
<div v-if="withCheckboxes"
|
||||||
|
class="sn-checkbox-icon"
|
||||||
|
:class="{
|
||||||
|
'checked': valueSelected(option[0]),
|
||||||
|
'unchecked': !valueSelected(option[0]),
|
||||||
|
}"
|
||||||
|
></div>
|
||||||
|
<div v-if="optionRenderer" v-html="optionRenderer(option)"></div>
|
||||||
|
<div v-else >{{ option[1] }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div v-if="filteredOptions.length === 0" class="text-sn-grey text-center py-2.5">
|
||||||
|
{{ noOptionsPlaceholder }}
|
||||||
|
</div>
|
||||||
|
</perfect-scrollbar>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { vOnClickOutside } from '@vueuse/components'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'SelectDropdown',
|
||||||
|
props: {
|
||||||
|
value: { type: [String, Number, Array] },
|
||||||
|
options: { type: Array, default: () => [] },
|
||||||
|
optionsUrl: { type: String },
|
||||||
|
placeholder: { type: String },
|
||||||
|
noOptionsPlaceholder: { type: String },
|
||||||
|
fewOptionsPlaceholder: { type: String },
|
||||||
|
allOptionsPlaceholder: { type: String },
|
||||||
|
optionRenderer: { type: Function },
|
||||||
|
labelRenderer: { type: Function },
|
||||||
|
disabled: { type: Boolean, default: false },
|
||||||
|
size: { type: String, default: 'md' },
|
||||||
|
multiple: { type: Boolean, default: false },
|
||||||
|
withCheckboxes: { type: Boolean, default: false },
|
||||||
|
searchable: { type: Boolean, default: false },
|
||||||
|
clearable: { type: Boolean, default: false },
|
||||||
|
},
|
||||||
|
directives: {
|
||||||
|
'click-outside': vOnClickOutside
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
newValue: null,
|
||||||
|
isOpen: false,
|
||||||
|
fetchedOptions: [],
|
||||||
|
selectAllState: 'unchecked',
|
||||||
|
query: '',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
sizeClass() {
|
||||||
|
switch (this.size) {
|
||||||
|
case 'xs':
|
||||||
|
return 'min-h-[36px]'
|
||||||
|
case 'sm':
|
||||||
|
return 'min-h-[40px]'
|
||||||
|
case 'md':
|
||||||
|
return 'min-h-[44px]'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
canClear() {
|
||||||
|
return this.clearable && this.label && this.isOpen
|
||||||
|
},
|
||||||
|
rawOptions() {
|
||||||
|
if (this.optionsUrl) {
|
||||||
|
return this.fetchedOptions
|
||||||
|
} else {
|
||||||
|
return this.options
|
||||||
|
}
|
||||||
|
},
|
||||||
|
filteredOptions() {
|
||||||
|
if (this.query.length > 0 && !this.optionsUrl ) {
|
||||||
|
return this.rawOptions.filter(option => {
|
||||||
|
return option[1].toLowerCase().includes(this.query.toLowerCase())
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return this.rawOptions
|
||||||
|
}
|
||||||
|
},
|
||||||
|
label() {
|
||||||
|
if (this.multiple) {
|
||||||
|
return this.multipleLabel
|
||||||
|
} else {
|
||||||
|
return this.singleLabel
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
singleLabel() {
|
||||||
|
const option = this.rawOptions.find(option => option[0] === this.newValue)
|
||||||
|
return this.renderLabel(option)
|
||||||
|
},
|
||||||
|
multipleLabel() {
|
||||||
|
if (!this.newValue) return false;
|
||||||
|
|
||||||
|
this.selectAllState = 'indeterminate'
|
||||||
|
|
||||||
|
if (this.newValue.length === 0) {
|
||||||
|
this.selectAllState = 'unchecked';
|
||||||
|
return false;
|
||||||
|
} else if (this.newValue.length === 1) {
|
||||||
|
return this.renderLabel(this.rawOptions.find(option => option[0] === this.newValue[0]))
|
||||||
|
} else if (this.newValue.length === this.rawOptions.length) {
|
||||||
|
this.selectAllState = 'checked';
|
||||||
|
return this.allOptionsPlaceholder
|
||||||
|
} else {
|
||||||
|
return `${this.newValue.length} ${this.fewOptionsPlaceholder}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
document.addEventListener('scroll', this.setPosition);
|
||||||
|
this.newValue = this.value;
|
||||||
|
if (!this.newValue && this.multiple) {
|
||||||
|
this.newValue = []
|
||||||
|
}
|
||||||
|
this.fetchOptions();
|
||||||
|
},
|
||||||
|
beforeUnmount() {
|
||||||
|
document.removeEventListener('scroll', this.setPosition);
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
isOpen() {
|
||||||
|
if (this.isOpen) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.setPosition();
|
||||||
|
this.$refs.search?.focus();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
query() {
|
||||||
|
if (this.optionsUrl) this.fetchOptions();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
renderLabel(option) {
|
||||||
|
if (!option) return false;
|
||||||
|
|
||||||
|
if (this.labelRenderer) {
|
||||||
|
return this.labelRenderer(option)
|
||||||
|
} else {
|
||||||
|
return option[1]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
valueSelected(value) {
|
||||||
|
if (!this.newValue) return false;
|
||||||
|
if (this.multiple) {
|
||||||
|
return this.newValue.includes(value);
|
||||||
|
} else {
|
||||||
|
return this.newValue == value;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
open() {
|
||||||
|
if (!this.disabled) this.isOpen = true
|
||||||
|
},
|
||||||
|
clear() {
|
||||||
|
this.newValue = null
|
||||||
|
this.query = '';
|
||||||
|
this.$emit('change', this.newValue)
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
this.isOpen = false
|
||||||
|
if (this.newValue != this.value) {
|
||||||
|
this.$emit('change', this.newValue)
|
||||||
|
}
|
||||||
|
this.query = '';
|
||||||
|
},
|
||||||
|
setValue(value) {
|
||||||
|
if(this.multiple) {
|
||||||
|
if (this.newValue.includes(value)) {
|
||||||
|
this.newValue = this.newValue.filter(v => v != value)
|
||||||
|
} else {
|
||||||
|
this.newValue.push(value)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.newValue = value
|
||||||
|
this.close()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selectAll() {
|
||||||
|
if (this.selectAllState === 'checked') {
|
||||||
|
this.newValue = []
|
||||||
|
} else {
|
||||||
|
this.newValue = this.rawOptions.map(option => option[0])
|
||||||
|
}
|
||||||
|
this.$emit('change', this.newValue)
|
||||||
|
},
|
||||||
|
setPosition() {
|
||||||
|
const field= this.$refs.field;
|
||||||
|
const flyout = this.$refs.flyout;
|
||||||
|
const rect = field.getBoundingClientRect();
|
||||||
|
const screenHeight = window.innerHeight;
|
||||||
|
|
||||||
|
if (!this.isOpen) return;
|
||||||
|
|
||||||
|
let width = rect.width;
|
||||||
|
let height = rect.height;
|
||||||
|
let top = rect.top + rect.height;
|
||||||
|
let bottom = screenHeight - rect.bottom + rect.height;
|
||||||
|
let left = rect.left;
|
||||||
|
|
||||||
|
flyout.style.width = `${width}px`;
|
||||||
|
flyout.style.top = `${top}px`;
|
||||||
|
flyout.style.left = `${left}px`;
|
||||||
|
if (bottom < top) {
|
||||||
|
flyout.style.marginTop = `${(height + flyout.offsetHeight)* -1}px`;
|
||||||
|
flyout.style.boxShadow = '0px -16px 32px 0px rgba(16, 24, 40, 0.07)';
|
||||||
|
} else {
|
||||||
|
flyout.style.marginTop = '';
|
||||||
|
flyout.style.boxShadow = '';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fetchOptions() {
|
||||||
|
if (this.optionsUrl) {
|
||||||
|
fetch(`${this.optionsUrl}?query=${this.query || ''}`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
this.fetchedOptions = data.data;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.setPosition();
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
218
app/views/design_elements/index.html.erb
Normal file
218
app/views/design_elements/index.html.erb
Normal file
|
|
@ -0,0 +1,218 @@
|
||||||
|
<div>
|
||||||
|
<h1>Select</h1>
|
||||||
|
<div id="selects" class="flex items-center gap-4 flex-wrap">
|
||||||
|
<div class="flex basis-full items-center gap-4">
|
||||||
|
<span>Sizes:</span>
|
||||||
|
<button class="btn btn-light" :class="{'!border-sn-blue': size == 'xs'}" @click="size = 'xs'">XS</button>
|
||||||
|
<button class="btn btn-light" :class="{'!border-sn-blue': size == 'sm'}" @click="size = 'sm'">SM</button>
|
||||||
|
<button class="btn btn-light" :class="{'!border-sn-blue': size == 'md'}" @click="size = 'md'">MD</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="w-64">
|
||||||
|
<label>Simple select</label>
|
||||||
|
<select-dropdown
|
||||||
|
:options="simpleOptions"
|
||||||
|
placeholder="Select an option"
|
||||||
|
:size="size"
|
||||||
|
></select-dropdown>
|
||||||
|
</div>
|
||||||
|
<div class="w-64">
|
||||||
|
<label>Simple select disabled</label>
|
||||||
|
<select-dropdown
|
||||||
|
:options="simpleOptions"
|
||||||
|
placeholder="Select an option"
|
||||||
|
:disabled="true"
|
||||||
|
:size="size"
|
||||||
|
></select-dropdown>
|
||||||
|
</div>
|
||||||
|
<div class="w-64">
|
||||||
|
<label>Simple select with long options</label>
|
||||||
|
<select-dropdown
|
||||||
|
:options="longOptions"
|
||||||
|
placeholder="Select an option"
|
||||||
|
:size="size"
|
||||||
|
></select-dropdown>
|
||||||
|
</div>
|
||||||
|
<div class="w-64">
|
||||||
|
<label>Simple select with predefined value</label>
|
||||||
|
<select-dropdown
|
||||||
|
value="5"
|
||||||
|
:options="simpleOptions"
|
||||||
|
placeholder="Select an option"
|
||||||
|
:size="size"
|
||||||
|
></select-dropdown>
|
||||||
|
</div>
|
||||||
|
<div class="w-64">
|
||||||
|
<label>Clearable select</label>
|
||||||
|
<select-dropdown
|
||||||
|
value="5"
|
||||||
|
:options="simpleOptions"
|
||||||
|
placeholder="Select an option"
|
||||||
|
:clearable="true"
|
||||||
|
:size="size"
|
||||||
|
></select-dropdown>
|
||||||
|
</div>
|
||||||
|
<div class="w-64">
|
||||||
|
<label>Simple select with search</label>
|
||||||
|
<select-dropdown
|
||||||
|
:options="simpleOptions"
|
||||||
|
placeholder="Select an option"
|
||||||
|
no-options-placeholder="No options found"
|
||||||
|
:searchable="true"
|
||||||
|
:size="size"
|
||||||
|
></select-dropdown>
|
||||||
|
</div>
|
||||||
|
<div class="w-64">
|
||||||
|
<label>Clearable select with search</label>
|
||||||
|
<select-dropdown
|
||||||
|
value="5"
|
||||||
|
:options="simpleOptions"
|
||||||
|
placeholder="Select an option"
|
||||||
|
:clearable="true"
|
||||||
|
:searchable="true"
|
||||||
|
:size="size"
|
||||||
|
></select-dropdown>
|
||||||
|
</div>
|
||||||
|
<div class="w-64">
|
||||||
|
<label>Multiselect</label>
|
||||||
|
<select-dropdown
|
||||||
|
:options="simpleOptions"
|
||||||
|
placeholder="Select an option"
|
||||||
|
few-options-placeholder="options selected"
|
||||||
|
all-options-placeholder="All options selected"
|
||||||
|
:multiple="true"
|
||||||
|
:size="size"
|
||||||
|
></select-dropdown>
|
||||||
|
</div>
|
||||||
|
<div class="w-64">
|
||||||
|
<label>Multiselect with predefined value</label>
|
||||||
|
<select-dropdown
|
||||||
|
:value="['5', '6', '2']"
|
||||||
|
:options="simpleOptions"
|
||||||
|
placeholder="Select an option"
|
||||||
|
few-options-placeholder="options selected"
|
||||||
|
all-options-placeholder="All options selected"
|
||||||
|
:multiple="true"
|
||||||
|
:size="size"
|
||||||
|
></select-dropdown>
|
||||||
|
</div>
|
||||||
|
<div class="w-64">
|
||||||
|
<label>Multiselect with checkboxes</label>
|
||||||
|
<select-dropdown
|
||||||
|
:options="simpleOptions"
|
||||||
|
placeholder="Select an option"
|
||||||
|
few-options-placeholder="options selected"
|
||||||
|
all-options-placeholder="All options selected"
|
||||||
|
:with-checkboxes="true"
|
||||||
|
:multiple="true"
|
||||||
|
:size="size"
|
||||||
|
></select-dropdown>
|
||||||
|
</div>
|
||||||
|
<div class="w-64">
|
||||||
|
<label>Multiselect with search</label>
|
||||||
|
<select-dropdown
|
||||||
|
:options="simpleOptions"
|
||||||
|
placeholder="Select an option"
|
||||||
|
few-options-placeholder="options selected"
|
||||||
|
all-options-placeholder="All options selected"
|
||||||
|
no-options-placeholder="No options found"
|
||||||
|
:searchable="true"
|
||||||
|
:multiple="true"
|
||||||
|
:size="size"
|
||||||
|
></select-dropdown>
|
||||||
|
</div>
|
||||||
|
<div class="w-64">
|
||||||
|
<label>Clearable multiselect</label>
|
||||||
|
<select-dropdown
|
||||||
|
:options="simpleOptions"
|
||||||
|
placeholder="Select an option"
|
||||||
|
few-options-placeholder="options selected"
|
||||||
|
all-options-placeholder="All options selected"
|
||||||
|
no-options-placeholder="No options found"
|
||||||
|
:clearable="true"
|
||||||
|
:multiple="true"
|
||||||
|
:size="size"
|
||||||
|
></select-dropdown>
|
||||||
|
</div>
|
||||||
|
<div class="w-64">
|
||||||
|
<label>Select with AJAX source</label>
|
||||||
|
<select-dropdown
|
||||||
|
options-url="<%= test_select_design_elements_path %>"
|
||||||
|
placeholder="Select an option"
|
||||||
|
no-options-placeholder="No options found"
|
||||||
|
:size="size"
|
||||||
|
></select-dropdown>
|
||||||
|
</div>
|
||||||
|
<div class="w-64">
|
||||||
|
<label>Select with AJAX with predefined</label>
|
||||||
|
<select-dropdown
|
||||||
|
value="5"
|
||||||
|
options-url="<%= test_select_design_elements_path %>"
|
||||||
|
placeholder="Select an option"
|
||||||
|
no-options-placeholder="No options found"
|
||||||
|
:size="size"
|
||||||
|
></select-dropdown>
|
||||||
|
</div>
|
||||||
|
<div class="w-64">
|
||||||
|
<label>Select with AJAX source with search</label>
|
||||||
|
<select-dropdown
|
||||||
|
options-url="<%= test_select_design_elements_path %>"
|
||||||
|
placeholder="Select an option"
|
||||||
|
no-options-placeholder="No options found"
|
||||||
|
|
||||||
|
:searchable="true"
|
||||||
|
:size="size"
|
||||||
|
></select-dropdown>
|
||||||
|
</div>
|
||||||
|
<div class="w-64">
|
||||||
|
<label>Multiselect with AJAX source</label>
|
||||||
|
<select-dropdown
|
||||||
|
options-url="<%= test_select_design_elements_path %>"
|
||||||
|
placeholder="Select an option"
|
||||||
|
no-options-placeholder="No options found"
|
||||||
|
few-options-placeholder="options selected"
|
||||||
|
all-options-placeholder="All options selected"
|
||||||
|
:size="size"
|
||||||
|
:multiple="true"
|
||||||
|
></select-dropdown>
|
||||||
|
</div>
|
||||||
|
<div class="w-64">
|
||||||
|
<label>Multiselect with AJAX/checkboxes</label>
|
||||||
|
<select-dropdown
|
||||||
|
options-url="<%= test_select_design_elements_path %>"
|
||||||
|
placeholder="Select an option"
|
||||||
|
no-options-placeholder="No options found"
|
||||||
|
few-options-placeholder="options selected"
|
||||||
|
all-options-placeholder="All options selected"
|
||||||
|
:size="size"
|
||||||
|
:multiple="true"
|
||||||
|
:with-checkboxes="true"
|
||||||
|
></select-dropdown>
|
||||||
|
</div>
|
||||||
|
<div class="w-64">
|
||||||
|
<label>Select with custom renderer</label>
|
||||||
|
<select-dropdown
|
||||||
|
:options="simpleOptions"
|
||||||
|
placeholder="Select an option"
|
||||||
|
:option-renderer="renderer"
|
||||||
|
:label-renderer="renderer"
|
||||||
|
:size="size"
|
||||||
|
></select-dropdown>
|
||||||
|
</div>
|
||||||
|
<div class="w-64">
|
||||||
|
<label>Multiselect with custom renderer</label>
|
||||||
|
<select-dropdown
|
||||||
|
:options="simpleOptions"
|
||||||
|
placeholder="Select an option"
|
||||||
|
:option-renderer="renderer"
|
||||||
|
:label-renderer="renderer"
|
||||||
|
few-options-placeholder="options selected"
|
||||||
|
all-options-placeholder="All options selected"
|
||||||
|
:multiple="true"
|
||||||
|
:size="size"
|
||||||
|
></select-dropdown>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%= javascript_include_tag 'vue_design_system_select' %>
|
||||||
|
|
@ -1010,4 +1010,12 @@ Rails.application.routes.draw do
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :gene_sequence_assets, only: %i(new create edit update)
|
resources :gene_sequence_assets, only: %i(new create edit update)
|
||||||
|
|
||||||
|
if Rails.env.development? || ENV['ENABLE_DESIGN_ELEMENTS'] == 'true'
|
||||||
|
resources :design_elements, only: %i(index) do
|
||||||
|
collection do
|
||||||
|
get :test_select
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@ const entryList = {
|
||||||
vue_legacy_datetime_picker: './app/javascript/packs/vue/legacy/datetime_picker.js',
|
vue_legacy_datetime_picker: './app/javascript/packs/vue/legacy/datetime_picker.js',
|
||||||
vue_label_templates_table: './app/javascript/packs/vue/label_templates_table.js',
|
vue_label_templates_table: './app/javascript/packs/vue/label_templates_table.js',
|
||||||
vue_projects_list: './app/javascript/packs/vue/projects_list.js',
|
vue_projects_list: './app/javascript/packs/vue/projects_list.js',
|
||||||
|
vue_design_system_select: './app/javascript/packs/vue/design_system/select.js'
|
||||||
}
|
}
|
||||||
|
|
||||||
// Engine pack loading based on https://github.com/rails/webpacker/issues/348#issuecomment-635480949
|
// Engine pack loading based on https://github.com/rails/webpacker/issues/348#issuecomment-635480949
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue