components/svg_explorer/svg_album.vue (151 lines of code) (raw):

<script> import { GlButton, GlEmptyState, GlSearchBoxByType, GlFormGroup, GlFormSelect, } from '../../helpers/gitlab_ui'; import { mapQueryFieldsToComputed, mapQueryFieldsToData, } from '../../helpers/sync_state_to_query_params'; import SvgCard from './svg_card.vue'; const DEFAULT_ICON_SIZE = 16; const queryFields = [ { field: 'searchString', param: 'q', default: '' }, { field: 'selectedSize', param: 'size', default: DEFAULT_ICON_SIZE }, ]; export default { components: { GlButton, GlEmptyState, GlSearchBoxByType, GlFormGroup, GlFormSelect, SvgCard, }, props: { elements: { type: Array, required: true, }, layout: { type: String, required: false, default: 'icons', }, sizeOptions: { type: Array, required: false, default: () => [], }, sourcePath: { type: String, required: false, default: '', }, }, data() { return { copyStatus: 0, ...mapQueryFieldsToData(queryFields), }; }, computed: { ...mapQueryFieldsToComputed(queryFields), filteredElements() { return this.elements.flatMap(({ name }) => { const isVisible = this.searchString?.startsWith('~') ? `~${name}` === this.searchString : name.includes(this.searchString); return isVisible ? name : []; }); }, copyStatusText() { switch (this.copyStatus) { case 1: return 'Copied to your clipboard!'; case -1: return "Copying didn't work :-("; default: return 'Click entry to copy their name'; } }, }, methods: { setSearchString(value) { this.searchString = `~${value}`; }, resetSearch() { this.searchString = ''; }, setCopyStatus(newStatus) { this.copyStatus = newStatus; setTimeout(() => { this.copyStatus = 0; }, 5000); }, }, }; </script> <template> <div> <header class="gl-mb-5"> <div class="gl-mb-4"> <h2 class="gl-heading-3 !gl-mb-1"> <slot name="header"></slot> </h2> <div>{{ copyStatusText }}</div> </div> <client-only> <div class="gl-flex gl-gap-3 sm:gl-flex-row"> <gl-form-group class="!gl-mb-0 gl-grow" label="Search" label-for="search"> <gl-search-box-by-type id="search" ref="input" v-model="searchString" autocomplete="off" spellcheck="false" :is-loading="false" /> </gl-form-group> <gl-form-group v-if="sizeOptions.length" class="!gl-mb-0" label="Select a size" label-for="size" > <gl-form-select id="size" v-model="selectedSize" :options="sizeOptions" /> </gl-form-group> </div> </client-only> </header> <div v-if="filteredElements.length" class="gl-grid gl-grid-cols-2 gl-gap-5 gl-p-0" :class="{ 'sm:gl-grid-cols-4 lg:gl-grid-cols-6': layout === 'icons', 'sm:gl-grid-cols-3': layout === 'illustrations', }" > <svg-card v-for="entry in elements" v-show="filteredElements.includes(entry.name)" :key="entry.name" :image="entry.name" :image-size="entry.size" :source-path="sourcePath" @imageCopied="setCopyStatus" @permalinkSelected="setSearchString" > <slot name="figure" :entry="entry" :size="Number(selectedSize)"></slot> </svg-card> </div> <gl-empty-state v-else title="No results found"> <template #actions> <gl-button @click.prevent="resetSearch">Reset search</gl-button> </template> </gl-empty-state> </div> </template>