diff --git a/package.json b/package.json index ec69f02b..09e9365e 100644 --- a/package.json +++ b/package.json @@ -19,10 +19,8 @@ "dependencies": { "@popperjs/core": "^2.11.6", "bootstrap": "^5.2.3", - "core-js": "^3.26.1", - "jquery": "^3.6.1", - "select2": "^4.0.13", - "select2-bootstrap-5-theme": "^1.3.0" + "choices.js": "^10.2.0", + "core-js": "^3.26.1" }, "devDependencies": { "@babel/core": "^7.20.2", diff --git a/resources/assets/js/forms.js b/resources/assets/js/forms.js index 8eab91fe..e6ee68d9 100644 --- a/resources/assets/js/forms.js +++ b/resources/assets/js/forms.js @@ -1,4 +1,4 @@ -import 'select2'; +import Choices from 'choices.js'; import { formatDay, formatTime } from './date'; import { ready } from './ready'; @@ -36,6 +36,22 @@ ready(() => { element.dispatchEvent(changeEvent); }; + /** + * Sets a select value and triggers a change. + * If the select has a Choices.js instances, it uses this instead to set the value. + * + * @param {HTMLSelectElement} element + * @param {*} value + */ + const setSelectValue = (element, value) => { + if (element.choices) { + element.choices.setChoiceByValue(value); + } + + element.value = value; + triggerChange(element); + }; + /** * Sets the values of the input fields with the IDs to from/to: * - date portion of from → start_day @@ -57,12 +73,10 @@ ready(() => { return; } - fromDay.value = formatDay(from); - triggerChange(fromDay); + setSelectValue(fromDay, formatDay(from)); fromTime.value = formatTime(from); - toDay.value = formatDay(to); - triggerChange(toDay); + setSelectValue(toDay, formatDay(to)); toTime.value = formatTime(to); }; @@ -214,9 +228,22 @@ ready(() => { }); ready(() => { - $('select').select2({ - theme: 'bootstrap-5', - width: '100%', + document.querySelectorAll('select').forEach((element) => { + element.choices = new Choices(element, { + allowHTML: false, + classNames: { + containerInner: 'choices__inner form-control', + }, + fuseOptions: { + distance: 0, + ignoreLocation: true, + includeScore: true, + threshold: 0, + }, + itemSelectText: '', + // do not use Number.MAX_SAFE_INTEGER here, because otherwise the script gets stuck + searchResultLimit: 9999, + }); }); }); diff --git a/resources/assets/js/vendor.js b/resources/assets/js/vendor.js index d056fcd5..3a657914 100644 --- a/resources/assets/js/vendor.js +++ b/resources/assets/js/vendor.js @@ -1,5 +1,4 @@ import 'core-js/stable'; -window.$ = window.jQuery = require('jquery'); window.bootstrap = require('bootstrap'); import './forms'; import './sticky-headers'; diff --git a/resources/assets/themes/base.scss b/resources/assets/themes/base.scss index 2130bb9e..c94d7c09 100644 --- a/resources/assets/themes/base.scss +++ b/resources/assets/themes/base.scss @@ -52,8 +52,7 @@ $form-label-font-weight: $font-weight-bold; @import '~bootstrap/scss/utilities/api'; @import '~bootstrap-icons/font/bootstrap-icons'; -@import '~select2/src/scss/core'; -@import '~select2-bootstrap-5-theme/src/include-all'; +@import 'choices'; @import 'error'; @import 'barchart'; @@ -160,14 +159,6 @@ table a > .icon-icon_angel { } } -.select2-dropdown { - background-color: $input-bg; - - .select2-search__field { - background-color: lighten($input-bg, 10%) !important; - } -} - // prevent dropdown-menu from overflowing the view .dropdown-menu { max-height: calc(100vh - 300px); // 300px: menu offset diff --git a/resources/assets/themes/choices.scss b/resources/assets/themes/choices.scss new file mode 100644 index 00000000..cd1bf211 --- /dev/null +++ b/resources/assets/themes/choices.scss @@ -0,0 +1,52 @@ +$choices-font-size-lg: $input-font-size-lg; +$choices-font-size-md: $input-font-size; +$choices-font-size-sm: $input-font-size-sm; + +$choices-border-radius: $input-border-radius; + +$choices-primary-color: $primary; +$choices-bg-color: $input-bg; +$choices-bg-color-dropdown: $input-bg; +$choices-text-color: $input-color; + +$es-choices-highlight-color: $choices-text-color !default; + +@import '~choices.js/src/styles/choices.scss'; + +.#{$choices-selector}__inner { + border: $input-border-width solid $input-border-color; + line-height: 0; + min-height: 0; + padding: $input-padding-y 1.75rem $input-padding-y $input-padding-x !important; +} + +.#{$choices-selector}__list--single { + padding: 0; +} + +.#{$choices-selector}__item { + line-height: 1.5; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.#{$choices-selector}__item--selectable { + padding-right: 10px !important; +} + +.#{$choices-selector}__item.is-selected { + color: $component-active-color; + background-color: $component-active-bg; +} + +.#{$choices-selector}__item.is-highlighted { + color: $es-choices-highlight-color; +} + +.#{$choices-selector}__input--cloned { + background-color: $input-bg !important; + border: 0; + box-shadow: none; + color: $input-color !important; +} diff --git a/resources/assets/themes/dark.scss b/resources/assets/themes/dark.scss index 57033f9e..5c0c8c9e 100644 --- a/resources/assets/themes/dark.scss +++ b/resources/assets/themes/dark.scss @@ -4,3 +4,5 @@ $input-disabled-bg: #111; $alert-bg-scale: 70%; $secondary: #222; $table-striped-bg: rgba(#fff, 0.05); + +$es-choices-highlight-color: #000; diff --git a/resources/views/pages/design.twig b/resources/views/pages/design.twig index ad15d441..76742ea0 100644 --- a/resources/views/pages/design.twig +++ b/resources/views/pages/design.twig @@ -240,7 +240,10 @@ {{ f.textarea('form-input-textarea', 'Textarea', {'rows': 2, 'value': lipsum}) }}
- {{ f.select('form-input-select', {'lorem': 'Ipsum', 'dolor': 'Sit'}, 'Select', 'dolor') }} + {{ f.select('form-input-select-1', {'opt1': 'Option 1', 'opt2': 'Option 2', 'opt3': 'Another option', 'opt4': 'A looooooooong item item item item'}, 'Select 1', 'opt1') }} + {{ f.select('form-input-select-2', {'sh': 'Bash', 'js': 'JavaScript', 'p': 'PHP', 'py': 'Python'}, 'Select 2', 'js') }} + {{ f.select('form-input-select-2', selectOptions, 'Select 3', 'Option 7') }} + {{ f.select('date-select', dateSelectOptions, 'Date select') }}
diff --git a/src/Controllers/DesignController.php b/src/Controllers/DesignController.php index e52cd187..d2d6b8fe 100644 --- a/src/Controllers/DesignController.php +++ b/src/Controllers/DesignController.php @@ -2,6 +2,7 @@ namespace Engelsystem\Controllers; +use Carbon\CarbonImmutable; use Engelsystem\Config\Config; use Engelsystem\Helpers\BarChart; use Engelsystem\Http\Response; @@ -40,27 +41,44 @@ class DesignController extends BaseController 'pronoun' => 'it/its', ])); + $selectOptions = []; + + for ($i = 1; $i <= 50; $i++) { + $selectOptions['option_' . $i] = 'Option ' . $i; + } + + $dateSelectOptions = []; + $date = CarbonImmutable::now(); + + for ($i = 1; $i <= 600; $i++) { + $formattedDate = $date->format("Y-m-d"); + $dateSelectOptions[$formattedDate] = $formattedDate; + $date = $date->addDay(); + } + $themes = $this->config->get('themes'); $date = new \DateTimeImmutable(); $data = [ - 'demo_user' => $demoUser, - 'demo_user_2' => $demoUser2, - 'themes' => $themes, - 'bar_chart' => BarChart::render(...BarChart::generateChartDemoData(23)), + 'demo_user' => $demoUser, + 'demo_user_2' => $demoUser2, + 'themes' => $themes, + 'bar_chart' => BarChart::render(...BarChart::generateChartDemoData(23)), - 'timestamp30m' => $date->add(new \DateInterval('PT30M')), - 'timestamp59m' => $date->add(new \DateInterval('PT59M')), - 'timestamp1h' => $date->add(new \DateInterval('PT1H')), - 'timestamp1h30m' => $date->add(new \DateInterval('PT1H30M')), - 'timestamp1h31m' => $date->add(new \DateInterval('PT1H31M')), - 'timestamp2h' => $date->add(new \DateInterval('PT2H')), - 'timestamp2d' => $date->add(new \DateInterval('P2D')), - 'timestamp3m' => $date->add(new \DateInterval('P3M')), - 'timestamp22y' => $date->add(new \DateInterval('P22Y')), - 'timestamp30s' => $date->add(new \DateInterval('PT30S')), + 'timestamp30m' => $date->add(new \DateInterval('PT30M')), + 'timestamp59m' => $date->add(new \DateInterval('PT59M')), + 'timestamp1h' => $date->add(new \DateInterval('PT1H')), + 'timestamp1h30m' => $date->add(new \DateInterval('PT1H30M')), + 'timestamp1h31m' => $date->add(new \DateInterval('PT1H31M')), + 'timestamp2h' => $date->add(new \DateInterval('PT2H')), + 'timestamp2d' => $date->add(new \DateInterval('P2D')), + 'timestamp3m' => $date->add(new \DateInterval('P3M')), + 'timestamp22y' => $date->add(new \DateInterval('P22Y')), + 'timestamp30s' => $date->add(new \DateInterval('PT30S')), - 'timestamp30mago' => $date->sub(new \DateInterval('PT30M')), - 'timestamp45mago' => $date->sub(new \DateInterval('PT45M')), + 'timestamp30mago' => $date->sub(new \DateInterval('PT30M')), + 'timestamp45mago' => $date->sub(new \DateInterval('PT45M')), + 'selectOptions' => $selectOptions, + 'dateSelectOptions' => $dateSelectOptions, ]; return $this->response->withView( diff --git a/yarn.lock b/yarn.lock index 0898879b..b96c771d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -871,7 +871,7 @@ "@babel/types" "^7.4.4" esutils "^2.0.2" -"@babel/runtime@^7.8.4": +"@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": version "7.20.7" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.7.tgz#fcb41a5a70550e04a7b708037c7c32f7f356d8fd" integrity sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ== @@ -1391,7 +1391,7 @@ bootstrap-icons@^1.10.2: resolved "https://registry.yarnpkg.com/bootstrap-icons/-/bootstrap-icons-1.10.3.tgz#c587b078ca6743bef4653fe90434b4aebfba53b2" integrity sha512-7Qvj0j0idEm/DdX9Q0CpxAnJYqBCFCiUI6qzSPYfERMcokVuV9Mdm/AJiVZI8+Gawe4h/l6zFcOzvV7oXCZArw== -bootstrap@^5.1.3, bootstrap@^5.2.3: +bootstrap@^5.2.3: version "5.2.3" resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-5.2.3.tgz#54739f4414de121b9785c5da3c87b37ff008322b" integrity sha512-cEKPM+fwb3cT8NzQZYEu4HilJ3anCrWqh3CHAok1p9jXqMPsPTBhU25fBckEJHJ/p+tTxTFTsFQGM+gaHpi3QQ== @@ -1463,6 +1463,15 @@ chalk@^4.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +choices.js@^10.2.0: + version "10.2.0" + resolved "https://registry.yarnpkg.com/choices.js/-/choices.js-10.2.0.tgz#3fe915a12b469a87b9552cd7158e413c8f65ab4f" + integrity sha512-8PKy6wq7BMjNwDTZwr3+Zry6G2+opJaAJDDA/j3yxvqSCnvkKe7ZIFfIyOhoc7htIWFhsfzF9tJpGUATcpUtPg== + dependencies: + deepmerge "^4.2.2" + fuse.js "^6.6.2" + redux "^4.2.0" + "chokidar@>=3.0.0 <4.0.0": version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" @@ -1711,6 +1720,11 @@ deep-is@^0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== +deepmerge@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" + integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== + doctrine@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" @@ -2042,6 +2056,11 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +fuse.js@^6.6.2: + version "6.6.2" + resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-6.6.2.tgz#fe463fed4b98c0226ac3da2856a415576dc9a111" + integrity sha512-cJaJkxCCxC8qIIcPBF9yGxY0W/tVZS3uEISDxhYIdtk8OL93pe+6Zj7LjCqVV4dzbqcriOZ+kQ/NE4RXZHsIGA== + gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -2238,11 +2257,6 @@ jest-worker@^27.0.2, jest-worker@^27.4.5: merge-stream "^2.0.0" supports-color "^8.0.0" -jquery@^3.6.1: - version "3.6.3" - resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.6.3.tgz#23ed2ffed8a19e048814f13391a19afcdba160e6" - integrity sha512-bZ5Sy3YzKo9Fyc8wH2iIQK4JImJ6R0GWI9kL1/k7Z91ZBNgkRXE6U0JfHIizZbort8ZunhSI3jw9I6253ahKfg== - js-sdsl@^4.1.4: version "4.2.0" resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.2.0.tgz#278e98b7bea589b8baaf048c20aeb19eb7ad09d0" @@ -2896,6 +2910,13 @@ rechoir@^0.7.0: dependencies: resolve "^1.9.0" +redux@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.0.tgz#46f10d6e29b6666df758780437651eeb2b969f13" + integrity sha512-oSBmcKKIuIR4ME29/AeNUnl5L+hvBq7OaJWzaptTQJAntaPvxIJqfnjbaEiCzzaIz+XmVILfqAM3Ob0aXLPfjA== + dependencies: + "@babel/runtime" "^7.9.2" + regenerate-unicode-properties@^10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz#7c3192cab6dd24e21cb4461e5ddd7dd24fa8374c" @@ -3065,18 +3086,6 @@ schema-utils@^4.0.0: ajv-formats "^2.1.1" ajv-keywords "^5.0.0" -select2-bootstrap-5-theme@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/select2-bootstrap-5-theme/-/select2-bootstrap-5-theme-1.3.0.tgz#b7126b01c4e2cfb5ee683b219820d49da31b4810" - integrity sha512-uEJDruP4tmwyKcs3V0oP7CIsyC45PGF5ddo8unwTp8OucJ1PSuTOBr+xbWaHTQPGnvp7N96psVQ5UBMQvFCcHA== - dependencies: - bootstrap "^5.1.3" - -select2@^4.0.13: - version "4.0.13" - resolved "https://registry.yarnpkg.com/select2/-/select2-4.0.13.tgz#0dbe377df3f96167c4c1626033e924372d8ef44d" - integrity sha512-1JeB87s6oN/TDxQQYCvS5EFoQyvV6eYMZZ0AeA4tdFDYWN3BAGZ8npr17UBFddU0lgAt3H0yjX3X6/ekOj1yjw== - semver@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"