From 745d551cc9253eae4e39e5d3406ceee051a7d6c1 Mon Sep 17 00:00:00 2001 From: Giulio Ganci Date: Sun, 8 May 2022 09:44:52 +0200 Subject: [PATCH 01/20] feat(UI): new BaseSelect component --- src/renderer/components/BaseSelect.vue | 251 +++++++++++++++++++++++++ 1 file changed, 251 insertions(+) create mode 100644 src/renderer/components/BaseSelect.vue diff --git a/src/renderer/components/BaseSelect.vue b/src/renderer/components/BaseSelect.vue new file mode 100644 index 00000000..92bedd9f --- /dev/null +++ b/src/renderer/components/BaseSelect.vue @@ -0,0 +1,251 @@ + + + + + From 22622df2cfcb71054c6f6110b7ad9d4f635553dc Mon Sep 17 00:00:00 2001 From: Giulio Ganci Date: Sun, 8 May 2022 09:45:37 +0200 Subject: [PATCH 02/20] feat(UI): initial BaseSelect integration --- .../WorkspaceAddConnectionPanel.vue | 20 ++++---- .../WorkspaceEditConnectionPanel.vue | 20 ++++---- src/renderer/scss/main.scss | 46 +++++++++++++++---- src/renderer/scss/themes/dark-theme.scss | 15 ++++-- src/renderer/scss/themes/light-theme.scss | 13 ++++++ 5 files changed, 79 insertions(+), 35 deletions(-) diff --git a/src/renderer/components/WorkspaceAddConnectionPanel.vue b/src/renderer/components/WorkspaceAddConnectionPanel.vue index b91935b1..82fa805a 100644 --- a/src/renderer/components/WorkspaceAddConnectionPanel.vue +++ b/src/renderer/components/WorkspaceAddConnectionPanel.vue @@ -50,19 +50,13 @@
- + />
@@ -404,12 +398,14 @@ import { useNotificationsStore } from '@/stores/notifications'; import { useWorkspacesStore } from '@/stores/workspaces'; import ModalAskCredentials from '@/components/ModalAskCredentials'; import BaseUploadInput from '@/components/BaseUploadInput'; +import BaseSelect from '@/components/BaseSelect.vue'; export default { name: 'WorkspaceAddConnectionPanel', components: { ModalAskCredentials, - BaseUploadInput + BaseUploadInput, + BaseSelect }, setup () { const { addConnection } = useConnectionsStore(); diff --git a/src/renderer/components/WorkspaceEditConnectionPanel.vue b/src/renderer/components/WorkspaceEditConnectionPanel.vue index fbb44c72..0e1bcecb 100644 --- a/src/renderer/components/WorkspaceEditConnectionPanel.vue +++ b/src/renderer/components/WorkspaceEditConnectionPanel.vue @@ -50,15 +50,13 @@
- +
@@ -401,12 +399,14 @@ import { useWorkspacesStore } from '@/stores/workspaces'; import Connection from '@/ipc-api/Connection'; import ModalAskCredentials from '@/components/ModalAskCredentials'; import BaseUploadInput from '@/components/BaseUploadInput'; +import BaseSelect from '@/components/BaseSelect.vue'; export default { name: 'WorkspaceEditConnectionPanel', components: { ModalAskCredentials, - BaseUploadInput + BaseUploadInput, + BaseSelect }, props: { connection: Object diff --git a/src/renderer/scss/main.scss b/src/renderer/scss/main.scss index d0f0cff9..e5fb7691 100644 --- a/src/renderer/scss/main.scss +++ b/src/renderer/scss/main.scss @@ -87,7 +87,6 @@ option:checked { } } - .workspace-query-results { overflow: auto; white-space: nowrap; @@ -209,17 +208,17 @@ option:checked { } } } - - .modal-overlay{ - background: rgba( 255, 255, 255, 0.1); - box-shadow: 0 8px 32px 0 rgba( 31, 38, 135, 0.37 ); + + .modal-overlay { + background: rgba(255, 255, 255, 0.1); + box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37); } } -#wrapper:not(.no-blur){ - .modal-overlay{ - backdrop-filter: blur( 4px ); - -webkit-backdrop-filter: blur( 4px ); +#wrapper:not(.no-blur) { + .modal-overlay { + backdrop-filter: blur(4px); + -webkit-backdrop-filter: blur(4px); } } @@ -297,6 +296,35 @@ option:checked { font-size: 0.7rem; padding: 1px 0.4rem 0; } + + &.select { + &.select-open { + border-color: $primary-color !important; + @include control-shadow(); + } + + .select__list-wrapper { + border: 1px solid transparent; + border-radius: $border-radius; + box-shadow: 0px 8px 17px 0px rgba(0, 0, 0, 0.2), 0px 6px 20px 0px rgba(0, 0, 0, 0.19); + } + + .select__list { + margin: 0; + li { + margin: 0; + padding: 0.3rem 0.8rem; + } + } + + .select__option--selected { + background: rgba($primary-color, 0.25); + } + + .select__option--highlight { + background: $primary-color; + } + } } .form-input[type="file"] { diff --git a/src/renderer/scss/themes/dark-theme.scss b/src/renderer/scss/themes/dark-theme.scss index 81628c38..665fd0fc 100644 --- a/src/renderer/scss/themes/dark-theme.scss +++ b/src/renderer/scss/themes/dark-theme.scss @@ -121,6 +121,15 @@ border-color: $primary-color; } + .form-select { + .select { + &__list-wrapper { + border-color: $bg-color-gray; + background-color: $bg-color-light-dark; + } + } + } + .form-input[readonly] { background-color: $bg-color-dark; cursor: default; @@ -232,7 +241,7 @@ } } } - + .connection-panel { .panel { background: rgba($bg-color-light-dark, 50%); @@ -240,9 +249,7 @@ } .bg-checkered { - background-image: - linear-gradient(to right, rgba(192, 192, 192, 0.75), rgba(192, 192, 192, 0.75)), - linear-gradient(to right, black 50%, white 50%), + background-image: linear-gradient(to right, rgba(192, 192, 192, 0.75), rgba(192, 192, 192, 0.75)), linear-gradient(to right, black 50%, white 50%), linear-gradient(to bottom, black 50%, white 50%); background-blend-mode: normal, difference, normal; background-size: 2em 2em; diff --git a/src/renderer/scss/themes/light-theme.scss b/src/renderer/scss/themes/light-theme.scss index bc0fe5a6..d9aa8a34 100644 --- a/src/renderer/scss/themes/light-theme.scss +++ b/src/renderer/scss/themes/light-theme.scss @@ -18,6 +18,19 @@ background: #ababab; } + .form-select { + .select { + &__list-wrapper { + border: #bcc3ce; + background-color: $body-bg; + } + + &__option--highlight { + color: $light-color; + } + } + } + .menu { .menu-item a { &:hover { From 5582a12bbfade75dbcc7f9d71ada7190ed08d3c2 Mon Sep 17 00:00:00 2001 From: Giulio Ganci Date: Sun, 8 May 2022 13:14:40 +0200 Subject: [PATCH 03/20] feat(UI): BaseSelect small variant --- src/renderer/scss/main.scss | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/renderer/scss/main.scss b/src/renderer/scss/main.scss index e5fb7691..7ce1c4da 100644 --- a/src/renderer/scss/main.scss +++ b/src/renderer/scss/main.scss @@ -317,6 +317,14 @@ option:checked { } } + &.select-sm { + .select__list { + li { + padding: 0.05rem 0.3rem; + } + } + } + .select__option--selected { background: rgba($primary-color, 0.25); } From a037d0cc0148444e8e6c5b87c79f6ba9c2a6f0fe Mon Sep 17 00:00:00 2001 From: Giulio Ganci Date: Sun, 8 May 2022 13:15:39 +0200 Subject: [PATCH 04/20] feat(UI): BaseSelect in table filters --- src/renderer/components/BaseSelect.vue | 5 ++- .../components/WorkspaceTabTableFilters.vue | 34 +++++++++---------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/renderer/components/BaseSelect.vue b/src/renderer/components/BaseSelect.vue index 92bedd9f..1c8290fc 100644 --- a/src/renderer/components/BaseSelect.vue +++ b/src/renderer/components/BaseSelect.vue @@ -128,12 +128,12 @@ export default defineComponent({ const getOptionValue = (opt) => { const key = typeof props.optionTrackBy === 'function' ? props.optionTrackBy() : props.optionTrackBy; - return opt[key]; + return key ? opt[key] : opt; }; const getOptionLabel = (opt) => { const key = typeof props.optionLabel === 'function' ? props.optionLabel() : props.optionLabel; - return opt[key]; + return key ? opt[key] : opt; }; const currentOptionLabel = computed(() => { @@ -221,7 +221,6 @@ export default defineComponent({ diff --git a/src/renderer/scss/main.scss b/src/renderer/scss/main.scss index 065090c1..17683722 100644 --- a/src/renderer/scss/main.scss +++ b/src/renderer/scss/main.scss @@ -318,6 +318,7 @@ option:checked { } .select__list-wrapper { + z-index: 401 !important; border: 1px solid transparent; border-radius: $border-radius; box-shadow: 0px 8px 17px 0px rgba(0, 0, 0, 0.2), 0px 6px 20px 0px rgba(0, 0, 0, 0.19); diff --git a/src/renderer/scss/themes/dark-theme.scss b/src/renderer/scss/themes/dark-theme.scss index 8cb4f1b4..7416e21e 100644 --- a/src/renderer/scss/themes/dark-theme.scss +++ b/src/renderer/scss/themes/dark-theme.scss @@ -126,6 +126,11 @@ border-color: $bg-color-gray; background-color: $bg-color-light-dark; } + + &__group { + background: rgba($bg-color-gray, 0.65); + color: rgba($bg-color-light-gray, 0.7); + } } .form-input[readonly] { diff --git a/src/renderer/scss/themes/light-theme.scss b/src/renderer/scss/themes/light-theme.scss index 63a129df..a547d1d8 100644 --- a/src/renderer/scss/themes/light-theme.scss +++ b/src/renderer/scss/themes/light-theme.scss @@ -24,6 +24,11 @@ background-color: $body-bg; } + &__group { + background: $bg-color-light-gray; + color: $unknown-color; + } + &__option--highlight { color: $light-color; } From 2b436d8613a1e3dff55d73adbddf5d2cd2452f27 Mon Sep 17 00:00:00 2001 From: Giulio Ganci Date: Tue, 10 May 2022 10:29:38 +0200 Subject: [PATCH 08/20] feat(UI): BaseSelect disabled state --- src/renderer/components/BaseSelect.vue | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/renderer/components/BaseSelect.vue b/src/renderer/components/BaseSelect.vue index 27ff8929..17a4064f 100644 --- a/src/renderer/components/BaseSelect.vue +++ b/src/renderer/components/BaseSelect.vue @@ -2,9 +2,9 @@
(opt) => { - for (const guess of ['id', 'value']) if (opt[guess]) return guess; - } + default: 'value' }, optionLabel: { type: [String, Function], - default: () => (opt) => opt.label ? 'label' : undefined + default: 'label' }, groupLabel: { type: String @@ -126,6 +124,10 @@ export default defineComponent({ }, dropdownClass: { type: String + }, + disabled: { + type: Boolean, + default: false } }, emits: ['select', 'open', 'close', 'update:modelValue', 'change', 'blur'], @@ -143,8 +145,10 @@ export default defineComponent({ const getOptionLabel = (opt) => _guess('optionLabel', opt); const _guess = (name, item) => { const prop = props[name]; - const key = typeof prop === 'function' ? prop(item) : prop; - return key ? item[key] : item; + if (typeof prop === 'function') + return prop(item); + + return item[prop] || item; }; const flattenOptions = computed(() => { @@ -231,7 +235,7 @@ export default defineComponent({ }; const activate = () => { - if (isOpen.value) return; + if (isOpen.value || props.disabled) return; isOpen.value = true; hightlightedIndex.value = flattenOptions.value.findIndex(el => el.value === internalValue.value) || 0; @@ -365,5 +369,9 @@ export default defineComponent({ list-style: none; } + &--disabled { + opacity: 0.6; + cursor: not-allowed; + } } From f7e04d633340a53420ce1c434e906c9434620e6e Mon Sep 17 00:00:00 2001 From: Giulio Ganci Date: Wed, 11 May 2022 22:57:13 +0200 Subject: [PATCH 09/20] feat(UI): BaseSelect supports disabled options --- src/renderer/components/BaseSelect.vue | 67 +++++++++++++++----------- 1 file changed, 40 insertions(+), 27 deletions(-) diff --git a/src/renderer/components/BaseSelect.vue b/src/renderer/components/BaseSelect.vue index 17a4064f..d26de2eb 100644 --- a/src/renderer/components/BaseSelect.vue +++ b/src/renderer/components/BaseSelect.vue @@ -48,8 +48,9 @@ :ref="(el) => optionRefs[index] = el" :class="{ 'select__group': opt.$type === 'group', - 'select__option--highlight': opt.$type === 'option' && index === hightlightedIndex, - 'select__option--selected': opt.$type === 'option' && isSelected(opt) + 'select__option--highlight': opt.$type === 'option' && !opt.disabled && index === hightlightedIndex, + 'select__option--selected': opt.$type === 'option' && isSelected(opt), + 'select__option--disabled': opt.disabled }" @click.stop="select(opt)" @mouseenter.self="hightlightedIndex = index" @@ -104,6 +105,9 @@ export default defineComponent({ type: [String, Function], default: 'label' }, + optionDisabled: { + type: Function + }, groupLabel: { type: String }, @@ -143,6 +147,7 @@ export default defineComponent({ const getOptionValue = (opt) => _guess('optionTrackBy', opt); const getOptionLabel = (opt) => _guess('optionLabel', opt); + const getOptionDisabled = (opt) => _guess('optionDisabled', opt); const _guess = (name, item) => { const prop = props[name]; if (typeof prop === 'function') @@ -167,6 +172,7 @@ export default defineComponent({ $type: 'option', label: getOptionLabel(el), id: `option-${value}`, + disabled: getOptionDisabled(el) === true, value, $data: { ...el @@ -180,6 +186,7 @@ export default defineComponent({ $type: 'option', label: getOptionLabel(curr), id: `option-${value}`, + disabled: getOptionDisabled(curr) === true, value, $data: { ...curr @@ -219,7 +226,7 @@ export default defineComponent({ ); const select = (opt) => { - if (opt.$type === 'group') return; + if (opt.$type === 'group' || opt.disabled) return; internalValue.value = opt.value; emit('select', opt); @@ -258,10 +265,10 @@ export default defineComponent({ isOpen.value = false; if (props.searchable) - searchInput.value.blur(); + searchInput.value?.blur(); else - el.value.blur(); + el.value?.blur(); if (!props.preserveSearch) searchText.value = ''; @@ -342,32 +349,38 @@ export default defineComponent({