{"version":3,"file":"stylesheets/6187.css?h=05e5a50f5aef3f1a3825","mappings":"AA+BA,+BAMA,+CAGA,sBANA,+BAEA,QACA,8BACA,WACA,YACA,qBACA,kBACA,CAEA,uDAZA,kEACA,yCAEA,oDAiBA,CARA,wBAKA,6CAEA,0BAJA,YAEA,uBACA,gBACA,wBACA,CCgDA,sBACA,iDAGA,+CAHA,oBACA,0CACA,qDACA,8BACA,UACA,CAEA,uBAEA,uCACA,4BAFA,YACA,YACA,2BACA,UACA,CAEA,wCACA,gBACA,mBACA,CAEA,wBACA,+CAGA,wDAEA,6CALA,mBACA,yCACA,YACA,uDACA,qDACA,uBACA,WACA,CAEA,+BACA,kCACA,CAEA,yCAEA,0BADA,8BACA,wBACA,CAEA,4CACA,gDACA,CAEA,8BAEA,8BAEA,0DACA,oDACA,aALA,sBAMA,CAEA,yEAEA,UACA,CCdA,mDACA,qDACA,kCACA,QACA,CACA,oDACA,uCACA,mFADA,WAEA,CACA,0DAEA,eADA,UAEA,CACA,4CACA,uCACA,qBAGA,YAFA,sBACA,UAEA,CCpIA,yCACA,0EACA,iBACA,CACA,6CACA,iBACA,cACA,eACA,CAEA,qBACA,cACA,YACA,eACA,UACA,CCbA,gDACA,gBACA,iBACA,CACA,4DAMA,qBAEA,4BAPA,wBAMA,oBAFA,eAHA,gBACA,uBACA,UAKA,CACA,qDACA,wDACA,CCYA,oBAIA,2CACA,kEAJA,qDACA,kCACA,SACA,2BAEA,gBACA,cACA","sources":["webpack://@studip/core/./resources/vue/components/ActiveFilter.vue","webpack://@studip/core/./resources/vue/components/SearchWithFilter.vue","webpack://@studip/core/./resources/vue/components/stock-images/SelectorSearch.vue","webpack://@studip/core/./resources/vue/components/stock-images/Thumbnail.vue","webpack://@studip/core/./resources/vue/components/stock-images/SelectableImageCard.vue","webpack://@studip/core/./resources/vue/components/stock-images/Selector.vue"],"sourcesContent":["<template>\n    <span class=\"activefilter\">\n        <slot></slot>\n        <button\n            @click=\"onRemoveActiveFilter\"\n            type=\"button\"\n            :title=\"$gettextInterpolate($gettext('Filter \\'%{name}\\' entfernen'), { name }, true)\"\n        >\n            <StudipIcon class=\"text-bottom\" shape=\"decline\" role=\"presentation\" alt=\"\" />\n        </button>\n    </span>\n</template>\n\n<script>\nimport StudipIcon from './StudipIcon.vue';\nexport default {\n    props: {\n        name: {\n            type: String,\n            required: true,\n        },\n    },\n    methods: {\n        onRemoveActiveFilter() {\n            this.$emit('remove');\n        },\n    },\n};\n</script>\n\n<style scoped>\n.activefilter {\n    align-items: center;\n    background-color: var(--content-color-20);\n    border: solid thin var(--black);\n    display: flex;\n    gap: 4px;\n    justify-content: space-between;\n    margin: 3px;\n    padding: 5px;\n    padding-inline-end: 0;\n    white-space: nowrap;\n}\n\nbutton {\n    align-items: center;\n    background-color: var(--content-color-20);\n    border: none;\n    display: flex;\n    justify-content: center;\n    margin-inline: 0;\n    padding-inline-start: 4px;\n}\n</style>\n","<template>\n    <div>\n        <form @submit.prevent=\"onSearch\">\n            <slot name=\"filters\"></slot>\n\n            <input\n                :id=\"`search-bar-input-${searchId}`\"\n                class=\"search-bar-input\"\n                type=\"text\"\n                v-model=\"searchTerm\"\n                :aria-label=\"$gettext('Geben Sie einen Suchbegriff mit mindestens 3 Zeichen ein.')\"\n            />\n\n            <button\n                v-if=\"showSearchResults\"\n                class=\"search-bar-erase\"\n                type=\"button\"\n                :title=\"$gettext('Suchformular zurücksetzen')\"\n                @click=\"onReset\"\n            >\n                <StudipIcon shape=\"decline\" :size=\"20\" />\n            </button>\n\n            <button\n                type=\"button\"\n                :title=\"$gettext('Suchfilter einstellen')\"\n                class=\"search-bar-filter\"\n                :class=\"{ active: showFilterPanel }\"\n                @click=\"onToggleFilterPanel\"\n                :aria-controls=\"`search-bar-filter-panel-${searchId}`\"\n                :aria-expanded=\"showFilterPanel ? 'true' : 'false'\"\n            >\n                <StudipIcon shape=\"filter\" :role=\"showFilterPanel ? 'info_alt' : 'clickable'\" :size=\"20\" alt=\"\" />\n            </button>\n\n            <button\n                type=\"submit\"\n                :value=\"$gettext('Suchen')\"\n                :aria-controls=\"`search-bar-input-${searchId}`\"\n                class=\"submit-search\"\n                :title=\"$gettext('Suche starten')\"\n            >\n                <StudipIcon shape=\"search\" :size=\"20\" role=\"presentation\" alt=\"\" />\n            </button>\n        </form>\n        <div :id=\"`search-bar-filter-panel-${searchId}`\" class=\"filterpanel\" ref=\"filterPanel\" v-if=\"showFilterPanel\">\n            <slot></slot>\n        </div>\n    </div>\n</template>\n\n<script>\nimport StudipIcon from './StudipIcon.vue';\n\nlet searchIndex = 0;\n\nexport default {\n    props: {\n        query: {\n            type: String,\n            required: true,\n        },\n    },\n    components: {\n        StudipIcon,\n    },\n    data: () => ({\n        searchId: searchIndex++,\n        showFilterPanel: false,\n        searchTerm: '',\n    }),\n    computed: {\n        showSearchResults() {\n            return this.query.length > 0;\n        },\n    },\n    methods: {\n        onReset() {\n            this.searchTerm = '';\n            this.onSearch();\n        },\n        onSearch() {\n            this.$emit('search', this.searchTerm);\n        },\n        onToggleFilterPanel() {\n            this.showFilterPanel = !this.showFilterPanel;\n        },\n    },\n    mounted() {\n        this.searchTerm = this.query;\n    },\n    watch: {\n        query(searchTerm) {\n            this.searchTerm = searchTerm;\n        },\n    },\n};\n</script>\n\n<style scoped>\nform {\n    align-items: stretch;\n    border: thin solid var(--content-color-40);\n    display: flex;\n    justify-content: space-between;\n    width: 100%;\n}\n\ninput {\n    border: none;\n    flex-grow: 1;\n    padding-inline-start: 0.75em;\n    width: 100%;\n}\n\ninput.search-bar-input {\n    line-height: 1.5;\n    padding-block: 0.25em;\n}\n\nbutton {\n    align-items: center;\n    background-color: var(--content-color-20);\n    border: none;\n    border-inline-start: thin solid var(--content-color-40);\n    display: flex;\n    justify-content: center;\n    width: 2.5em;\n}\n\nbutton.active {\n    background-color: var(--base-color);\n}\n\nbutton.search-bar-erase {\n    background-color: var(--white);\n    border-inline-start: none;\n}\n\n.search-bar-filter--remove {\n    margin-inline-start: 5px;\n}\n\n.filterpanel {\n    width: calc(100% + 2px);\n    background-color: var(--white);\n    border: thin solid var(--content-color-40);\n    border-top: none;\n    box-sizing: border-box;\n    padding: 10px;\n}\n\n.filterpanel::before,\n.filterpanel::after {\n    right: 50px;\n}\n</style>\n","<template>\n    <SearchWithFilter :query=\"query\" @search=\"onSearch\">\n        <template #filters>\n            <ActiveFilter\n                v-if=\"hasOrientationFilter\"\n                :name=\"orientations[orientation].text\"\n                @remove=\"onRemoveOrientationFilter()\"\n            >\n                {{ orientations[orientation].text }}\n            </ActiveFilter>\n\n            <ActiveFilter\n                v-for=\"color in selectedColors\"\n                :key=\"color.hex\"\n                :name=\"$gettextInterpolate($gettext('Farbe %{color}'), { color: color.name })\"\n                @remove=\"onRemoveColorFilter(color)\"\n            >\n                <label>\n                    <b class=\"stock-images-color-patch\" :style=\"`background-color: ${color.hex}`\"></b>\n                </label>\n            </ActiveFilter>\n        </template>\n\n        <div class=\"stock-images-search-filter-panel\">\n            <div>\n                <label>\n                    <div>{{ $gettext('Seitenausrichtung') }}</div>\n\n                    <select v-model=\"orientation\">\n                        <option v-for=\"[key, value] in Object.entries(orientations)\" :value=\"key\" :key=\"`orientation-option-${key}`\">\n                            {{ value.text }}\n                        </option>\n                    </select>\n                </label>\n            </div>\n\n            <div>\n                <div>{{ $gettext('Farbfilter') }}</div>\n\n                <studip-select\n                    multiple\n                    v-model=\"selectedColors\"\n                    :options=\"selectableColors\"\n                    label=\"name\"\n                >\n                    <template #open-indicator>\n                        <span><studip-icon shape=\"arr_1down\" :size=\"10\" /></span>\n                    </template>\n\n                    <template #option=\"option\">\n                        <span class=\"vs__option-color\" :style=\"{ 'background-color': option.hex }\"></span>\n                        <span>{{ option.name }}</span>\n                    </template>\n\n                    <template #selected-option-container>{{ ' ' }}</template>\n\n                    <template #no-options>{{ $gettext('Keine Auswahlmöglichkeiten') }}</template>\n                </studip-select>\n            </div>\n        </div>\n    </SearchWithFilter>\n</template>\n\n<script>\nimport ActiveFilter from '../ActiveFilter.vue';\nimport SearchWithFilter from '../SearchWithFilter.vue';\nimport { colors as selectableColors } from './colors.js';\nimport { orientations, similarColors } from './filters.js';\n\nexport default {\n    props: {\n        activeFilters: {\n            type: Object,\n            required: true,\n        },\n        query: {\n            type: String,\n            required: true,\n        },\n    },\n    components: {\n        ActiveFilter,\n        SearchWithFilter,\n    },\n    data: () => ({\n        orientation: 'any',\n        selectedColors: [],\n    }),\n    computed: {\n        hasOrientationFilter() {\n            return this.orientation && this.orientation !== 'any';\n        },\n        orientations: () => orientations,\n        selectableColors: () => selectableColors,\n        showSearchResults() {\n            return this.query.length > 0;\n        },\n    },\n    methods: {\n        onRemoveColorFilter(color) {\n            this.selectedColors = this.selectedColors.filter((clr) => clr.hex !== color.hex);\n            this.updateActiveFilters();\n        },\n        onRemoveOrientationFilter() {\n            this.orientation = 'any';\n        },\n        onReset() {\n            this.onSearch();\n        },\n        onSearch(searchTerm = null) {\n            this.$emit('search', searchTerm);\n        },\n        resetLocalFilters() {\n            this.selectedColors = this.activeFilters?.colors\n                ? this.selectableColors.filter(({ hex }) => this.activeFilters.colors.includes(hex))\n                : [];\n            this.orientation = this.activeFilters?.orientation ?? 'any';\n        },\n        updateActiveFilters() {\n            const activeFilters = {\n                colors: this.selectedColors.map(({ hex }) => hex),\n                orientation: this.orientation,\n            };\n            this.$emit('update-active-filters', activeFilters);\n        },\n    },\n    mounted() {\n        this.resetLocalFilters();\n    },\n    watch: {\n        activeFilters() {\n            this.resetLocalFilters();\n        },\n        orientation(newVal, oldVal) {\n            this.updateActiveFilters();\n        },\n    },\n};\n</script>\n\n<style scoped>\n.stock-images-search-filter-panel {\n    display: flex;\n    flex-wrap: wrap;\n    gap: 2rem;\n}\n.stock-images-search-filter-panel > * {\n    flex-grow: 1;\n    flex-basis: calc((30rem - 100%) * 999);\n}\n.stock-images-search-filter-panel select {\n    width: 100%;\n    max-width: 48em;\n}\nb.stock-images-color-patch {\n    border: solid thin var(--base-color-20);\n    display: inline-block;\n    vertical-align: bottom;\n    width: 20px;\n    height: 20px;\n}\n</style>\n","<template>\n    <div class=\"stock-images-thumbnail\" v-if=\"url\">\n        <div :style=\"{ width }\">\n            <img :src=\"url\" :style=\"{ 'object-fit': contain ? 'contain' : 'cover' }\" role=\"presentation\" />\n        </div>\n    </div>\n</template>\n\n<script>\nexport default {\n    props: {\n        url: {\n            type: String,\n            required: true,\n        },\n        width: {\n            type: String,\n            default: '6rem',\n        },\n        contain: {\n            type: Boolean,\n            default: false\n        }\n    },\n};\n</script>\n\n<style scoped>\n.stock-images-thumbnail {\n    display: inline-flex;\n    position: relative;\n}\n.stock-images-thumbnail > div {\n    aspect-ratio: 1/1;\n    display: block;\n    overflow: hidden;\n}\n\nimg {\n    display: block;\n    height: 100%;\n    max-width: 100%;\n    width: 100%;\n}\n</style>\n","<template>\n    <div class=\"stock-images-selectable-image\" tabindex=\"0\">\n        <Thumbnail :url=\"thumbnailUrl\" contain class=\"stock-images-image-card__thumbnail\" width=\"8rem\" />\n        <div>{{ stockImage.attributes?.title ?? '' }}</div>\n    </div>\n</template>\n\n<script>\nimport Thumbnail from './Thumbnail.vue';\n\nexport default {\n    props: {\n        stockImage: {\n            type: Object,\n            required: true,\n        },\n    },\n    components: { Thumbnail },\n    computed: {\n        thumbnailUrl() {\n            return (\n                this.stockImage.attributes['download-urls'].small ??\n                this.stockImage.attributes['download-urls'].original\n            );\n        },\n    },\n};\n</script>\n\n<style scoped>\n.stock-images-selectable-image {\n    overflow: hidden;\n    position: relative;\n}\n.stock-images-selectable-image > :last-child {\n    background: var(--white);\n    overflow: hidden;\n    text-overflow: ellipsis;\n    width: 8rem;\n    min-height: 3em;\n    -webkit-line-clamp: 2;\n    display: -webkit-box;\n    -webkit-box-orient: vertical;\n}\n.stock-images-image-card__thumbnail {\n    background-image: url(../images/checkered-background.png);\n}\n</style>\n","<template>\n    <div>\n        <div>\n            <SelectorSearch\n                :active-filters=\"activeFilters\"\n                :query=\"query\"\n                @search=\"onSearch\"\n                @update-active-filters=\"onUpdateActiveFilters\"\n            />\n        </div>\n        <ul>\n            <li v-for=\"stockImage in filteredStockImages\" :key=\"stockImage.id\">\n                <SelectableImageCard :stock-image=\"stockImage\" @click.native=\"onSelectImage(stockImage)\" @keyup.enter.native=\"onSelectImage(stockImage)\" />\n            </li>\n        </ul>\n    </div>\n</template>\n\n<script>\nimport SelectorSearch from './SelectorSearch.vue';\nimport SelectableImageCard from './SelectableImageCard.vue';\nimport { searchFilterAndSortImages } from './filters.js';\n\nexport default {\n    props: {\n        stockImages: {\n            type: Array,\n            required: true,\n        },\n    },\n    data: () => ({\n        activeFilters: {\n            colors: [],\n            orientation: 'landscape',\n        },\n        query: '',\n    }),\n    components: { SelectorSearch, SelectableImageCard },\n    computed: {\n        filteredStockImages() {\n            return searchFilterAndSortImages(this.stockImages, this.query, this.activeFilters);\n        },\n    },\n    methods: {\n        onUpdateActiveFilters(activeFilters) {\n            this.activeFilters = activeFilters;\n        },\n        onSearch(query) {\n            this.query = query;\n        },\n        onSelectImage(stockImage) {\n            this.$emit('select', stockImage);\n        },\n    },\n};\n</script>\n\n<style scoped>\nul {\n    display: flex;\n    flex-wrap: wrap;\n    gap: 1rem;\n    justify-content: flex-start;\n    align-items: center;\n    list-style: none;\n    padding: 1rem 0;\n}\n</style>\n"],"names":[],"sourceRoot":""}