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>