Merge pull request #901 from tainacan/feature/900
Creates Mosaic View Mode #900
This commit is contained in:
commit
1fe3617d2a
|
@ -132,7 +132,7 @@ class Collections extends Repository {
|
||||||
'title' => __( 'Enabled view modes', 'tainacan' ),
|
'title' => __( 'Enabled view modes', 'tainacan' ),
|
||||||
'type' => 'array',
|
'type' => 'array',
|
||||||
'description' => __( 'Which visualization modes will be available for the public to choose from', 'tainacan' ),
|
'description' => __( 'Which visualization modes will be available for the public to choose from', 'tainacan' ),
|
||||||
'default' => [ 'table', 'cards' ],
|
'default' => [ 'table', 'cards', 'masonry' ],
|
||||||
'items' => [ 'type' => 'string' ],
|
'items' => [ 'type' => 'string' ],
|
||||||
//'validation' => v::stringType(),
|
//'validation' => v::stringType(),
|
||||||
],
|
],
|
||||||
|
|
|
@ -2485,5 +2485,23 @@ class Theme_Helper {
|
||||||
'requires_thumbnail' => false,
|
'requires_thumbnail' => false,
|
||||||
'placeholder_template' => $map_view_mode_placeholder
|
'placeholder_template' => $map_view_mode_placeholder
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$this->register_view_mode('mosaic', [
|
||||||
|
'label' => __('Mosaic', 'tainacan'),
|
||||||
|
'dynamic_metadata' => false,
|
||||||
|
'description' => __('A mosaic view, similar to Flickr and Google Photos, which will display images without cropping.', 'tainacan'),
|
||||||
|
'icon' => '<span class="icon"><i class="tainacan-icon tainacan-icon-viewmasonry tainacan-icon-rotate-90 tainacan-icon-1-25em"></i></span>',
|
||||||
|
'type' => 'component',
|
||||||
|
'implements_skeleton' => true,
|
||||||
|
'placeholder_template' => '<ul style="list-style: none;width: 100%; height: auto; display: flex; gap: 24px 0; flex-wrap: wrap;">' .
|
||||||
|
array_reduce( range(0,11), function($container, $i) {
|
||||||
|
$container .= '<li style="flex-grow: 1; max-width: 35%; width: ' . ($i % 2 == 0 ? rand(100, 180) : rand(90, 170)) . 'px; height: 120px ; background-color: var(--tainacan-block-gray1, #f2f2f2); margin: 0; padding: 5px;">
|
||||||
|
<div style="width: 100%;height: 100%; background-color: var(--tainacan-block-gray2, #dbdbdb);margin-bottom: 10px;"></div>
|
||||||
|
<div style="width: 100%;height: 10px; background-color: var(--tainacan-block-gray3, #a5a5a5);"></div>
|
||||||
|
</li>';
|
||||||
|
return $container;
|
||||||
|
}) .
|
||||||
|
'</ul>'
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1979,6 +1979,181 @@
|
||||||
</l-control>
|
</l-control>
|
||||||
</l-map>
|
</l-map>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- MOSAIC VIEW MODE -->
|
||||||
|
<ul
|
||||||
|
v-if="viewMode == 'mosaic'"
|
||||||
|
:class="{
|
||||||
|
'hide-items-selection': $adminOptions.hideItemsListSelection
|
||||||
|
}"
|
||||||
|
class="tainacan-mosaic-container">
|
||||||
|
<li
|
||||||
|
v-for="(item, index) of items"
|
||||||
|
:key="index"
|
||||||
|
:data-tainacan-item-id="item.id"
|
||||||
|
:style="{
|
||||||
|
'--tainacan-mosaic-item-width': getAcceptableWidthBasedOnRatio(item['thumbnail'], 'tainacan-large-full', 300),
|
||||||
|
'--tainacan-mosaic-item-height': $thumbHelper.getHeight(item['thumbnail'], 'tainacan-large-full', 300)
|
||||||
|
}">
|
||||||
|
<div
|
||||||
|
:class="{
|
||||||
|
'selected-mosaic-item': getSelectedItemChecked(item.id) == true
|
||||||
|
}"
|
||||||
|
class="tainacan-mosaic-item"
|
||||||
|
@click.left="onClickItem($event, item)"
|
||||||
|
@click.right="onRightClickItem($event, item)">
|
||||||
|
|
||||||
|
<!-- Thumbnail -->
|
||||||
|
<blur-hash-image
|
||||||
|
v-if="item.thumbnail != undefined"
|
||||||
|
class="tainacan-mosaic-item-thumbnail"
|
||||||
|
:width="$thumbHelper.getWidth(item['thumbnail'], 'tainacan-large-full', 320)"
|
||||||
|
:height="$thumbHelper.getHeight(item['thumbnail'], 'tainacan-large-full', 320)"
|
||||||
|
:hash="$thumbHelper.getBlurhashString(item['thumbnail'], 'tainacan-large-full')"
|
||||||
|
:src="$thumbHelper.getSrc(item['thumbnail'], 'tainacan-large-full', item.document_mimetype)"
|
||||||
|
:srcset="$thumbHelper.getSrcSet(item['thumbnail'], 'tainacan-large-full', item.document_mimetype)"
|
||||||
|
:alt="item.thumbnail_alt ? item.thumbnail_alt : $i18n.get('label_thumbnail')"
|
||||||
|
:transition-duration="500"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- Checkbox -->
|
||||||
|
<!-- TODO: Remove v-if="collectionId" from this element when the bulk edit in repository is done -->
|
||||||
|
<div
|
||||||
|
v-if="collectionId && !$adminOptions.hideItemsListSelection && ($adminOptions.itemsSingleSelectionMode || $adminOptions.itemsMultipleSelectionMode || (collection && collection.current_user_can_bulk_edit))"
|
||||||
|
:class="{ 'is-selecting': isSelectingItems }"
|
||||||
|
class="mosaic-item-checkbox">
|
||||||
|
<label
|
||||||
|
tabindex="0"
|
||||||
|
:class="(!$adminOptions.itemsSingleSelectionMode ? 'b-checkbox checkbox' : 'b-radio radio') + ' is-small'">
|
||||||
|
<input
|
||||||
|
v-if="!$adminOptions.itemsSingleSelectionMode"
|
||||||
|
type="checkbox"
|
||||||
|
:checked="getSelectedItemChecked(item.id)"
|
||||||
|
@input="setSelectedItemChecked(item.id)">
|
||||||
|
<input
|
||||||
|
v-else
|
||||||
|
v-model="singleItemSelection"
|
||||||
|
type="radio"
|
||||||
|
name="item-single-selection"
|
||||||
|
:value="item.id">
|
||||||
|
<span class="check" />
|
||||||
|
<span class="control-label" />
|
||||||
|
<span class="sr-only">{{ $i18n.get('label_select_item') }}</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Title -->
|
||||||
|
<div
|
||||||
|
class="metadata-title"
|
||||||
|
:style="{
|
||||||
|
'padding-left': !collectionId || !($adminOptions.itemsSingleSelectionMode || $adminOptions.itemsMultipleSelectionMode || (collection && collection.current_user_can_bulk_edit)) || $adminOptions.itemsSearchSelectionMode ? '0 !important' : (isOnAllItemsTabs ? '0.5em' : '1em')
|
||||||
|
}">
|
||||||
|
<p
|
||||||
|
v-tooltip="{
|
||||||
|
delay: {
|
||||||
|
show: 750,
|
||||||
|
hide: 100,
|
||||||
|
},
|
||||||
|
content: item.title != undefined ? item.title : '',
|
||||||
|
html: true,
|
||||||
|
placement: 'auto-start',
|
||||||
|
popperClass: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'tainacan-repository-tooltip' : '']
|
||||||
|
}">
|
||||||
|
<span
|
||||||
|
v-if="isOnAllItemsTabs && $statusHelper.hasIcon(item.status)"
|
||||||
|
v-tooltip="{
|
||||||
|
content: $i18n.get('status_' + item.status),
|
||||||
|
autoHide: true,
|
||||||
|
popperClass: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'tainacan-repository-tooltip' : ''],
|
||||||
|
placement: 'auto-start'
|
||||||
|
}"
|
||||||
|
class="icon has-text-gray">
|
||||||
|
<i
|
||||||
|
class="tainacan-icon tainacan-icon-1em"
|
||||||
|
:class="$statusHelper.getIcon(item.status)"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
{{ item.title != undefined ? item.title : '' }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<div
|
||||||
|
v-if="item.current_user_can_edit && !$adminOptions.hideItemsListActionAreas"
|
||||||
|
class="actions-area"
|
||||||
|
:label="$i18n.get('label_actions')">
|
||||||
|
<a
|
||||||
|
v-if="!isOnTrash"
|
||||||
|
id="button-edit"
|
||||||
|
:aria-label="$i18n.getFrom('items','edit_item')"
|
||||||
|
@click.prevent.stop="goToItemEditPage(item)">
|
||||||
|
<span
|
||||||
|
v-tooltip="{
|
||||||
|
content: $i18n.get('edit'),
|
||||||
|
autoHide: true,
|
||||||
|
placement: 'auto',
|
||||||
|
popperClass: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'tainacan-repository-tooltip' : '']
|
||||||
|
}"
|
||||||
|
class="icon">
|
||||||
|
<i class="has-text-secondary tainacan-icon tainacan-icon-1-25em tainacan-icon-edit" />
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
v-if="isOnTrash"
|
||||||
|
:aria-lavel="$i18n.get('label_button_untrash')"
|
||||||
|
@click.prevent.stop="untrashOneItem(item.id)">
|
||||||
|
<span
|
||||||
|
v-tooltip="{
|
||||||
|
content: $i18n.get('label_recover_from_trash'),
|
||||||
|
autoHide: true,
|
||||||
|
placement: 'auto',
|
||||||
|
popperClass: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'tainacan-repository-tooltip' : '']
|
||||||
|
}"
|
||||||
|
class="icon">
|
||||||
|
<i class="has-text-secondary tainacan-icon tainacan-icon-1-25em tainacan-icon-undo" />
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
v-if="item.current_user_can_delete"
|
||||||
|
id="button-delete"
|
||||||
|
:aria-label="$i18n.get('label_button_delete')"
|
||||||
|
@click.prevent.stop="deleteOneItem(item.id)">
|
||||||
|
<span
|
||||||
|
v-tooltip="{
|
||||||
|
content: isOnTrash ? $i18n.get('label_delete_permanently') : $i18n.get('delete'),
|
||||||
|
autoHide: true,
|
||||||
|
placement: 'auto',
|
||||||
|
popperClass: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'tainacan-repository-tooltip' : '']
|
||||||
|
}"
|
||||||
|
class="icon">
|
||||||
|
<i
|
||||||
|
:class="{ 'tainacan-icon-delete': !isOnTrash, 'tainacan-icon-deleteforever': isOnTrash }"
|
||||||
|
class="has-text-secondary tainacan-icon tainacan-icon-1-25em" />
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
v-if="!isOnTrash"
|
||||||
|
id="button-open-external"
|
||||||
|
:aria-label="$i18n.getFrom('items','view_item')"
|
||||||
|
target="_blank"
|
||||||
|
:href="item.url"
|
||||||
|
@click.stop="">
|
||||||
|
<span
|
||||||
|
v-tooltip="{
|
||||||
|
content: $i18n.get('label_item_page_on_website'),
|
||||||
|
autoHide: true,
|
||||||
|
popperClass: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'tainacan-repository-tooltip' : ''],
|
||||||
|
placement: 'auto',
|
||||||
|
html: true
|
||||||
|
}"
|
||||||
|
class="icon">
|
||||||
|
<i class="tainacan-icon tainacan-icon-1-125em tainacan-icon-openurl" />
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -2674,6 +2849,12 @@ export default {
|
||||||
duration: 3000
|
duration: 3000
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
getAcceptableWidthBasedOnRatio(thumbnail, size, defaultSize) {
|
||||||
|
const width = this.$thumbHelper.getWidth(thumbnail, size, defaultSize);
|
||||||
|
const height = this.$thumbHelper.getHeight(thumbnail, size, defaultSize);
|
||||||
|
|
||||||
|
return (width / height) > 0.7 ? width : ( height * 0.7 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2685,6 +2866,7 @@ export default {
|
||||||
@import "../../scss/_tables.scss";
|
@import "../../scss/_tables.scss";
|
||||||
@import "../../scss/_view-mode-cards.scss";
|
@import "../../scss/_view-mode-cards.scss";
|
||||||
@import "../../scss/_view-mode-masonry.scss";
|
@import "../../scss/_view-mode-masonry.scss";
|
||||||
|
@import "../../scss/_view-mode-mosaic.scss";
|
||||||
@import "../../scss/_view-mode-grid.scss";
|
@import "../../scss/_view-mode-grid.scss";
|
||||||
@import "../../scss/_view-mode-records.scss";
|
@import "../../scss/_view-mode-records.scss";
|
||||||
@import "../../scss/_view-mode-list.scss";
|
@import "../../scss/_view-mode-list.scss";
|
||||||
|
|
|
@ -226,13 +226,13 @@
|
||||||
show: 500,
|
show: 500,
|
||||||
hide: 300,
|
hide: 300,
|
||||||
},
|
},
|
||||||
content: (totalItems <= 0 || adminViewMode == 'grid'|| adminViewMode == 'cards' || adminViewMode == 'masonry') ? (adminViewMode == 'grid'|| adminViewMode == 'cards' || adminViewMode == 'masonry') ? $i18n.get('info_current_view_mode_metadata_not_allowed') : $i18n.get('info_cant_select_metadata_without_items') : '',
|
content: (totalItems <= 0 || adminViewMode == 'grid'|| adminViewMode == 'cards' || adminViewMode == 'masonry' || adminViewMode == 'mosaic') ? (adminViewMode == 'grid'|| adminViewMode == 'cards' || adminViewMode == 'masonry' || adminViewMode == 'mosaic') ? $i18n.get('info_current_view_mode_metadata_not_allowed') : $i18n.get('info_cant_select_metadata_without_items') : '',
|
||||||
autoHide: false,
|
autoHide: false,
|
||||||
placement: 'auto-start',
|
placement: 'auto-start',
|
||||||
popperClass: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'tainacan-repository-tooltip' : '']
|
popperClass: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'tainacan-repository-tooltip' : '']
|
||||||
}"
|
}"
|
||||||
:mobile-modal="true"
|
:mobile-modal="true"
|
||||||
:disabled="totalItems <= 0 || adminViewMode == 'grid'|| adminViewMode == 'cards' || adminViewMode == 'masonry'"
|
:disabled="totalItems <= 0 || adminViewMode == 'grid'|| adminViewMode == 'cards' || adminViewMode == 'masonry' || adminViewMode == 'mosaic'"
|
||||||
class="show metadata-options-dropdown"
|
class="show metadata-options-dropdown"
|
||||||
aria-role="list"
|
aria-role="list"
|
||||||
trap-focus>
|
trap-focus>
|
||||||
|
@ -383,12 +383,15 @@
|
||||||
<span class="view-mode-icon icon is-small gray-icon">
|
<span class="view-mode-icon icon is-small gray-icon">
|
||||||
<i
|
<i
|
||||||
v-if="adminViewMode !== 'map'"
|
v-if="adminViewMode !== 'map'"
|
||||||
:class="{'tainacan-icon-viewtable' : ( adminViewMode == 'table' || adminViewMode == undefined),
|
:class="{
|
||||||
|
'tainacan-icon-viewtable' : ( adminViewMode == 'table' || adminViewMode == undefined),
|
||||||
'tainacan-icon-viewcards' : adminViewMode == 'cards',
|
'tainacan-icon-viewcards' : adminViewMode == 'cards',
|
||||||
'tainacan-icon-viewminiature' : adminViewMode == 'grid',
|
'tainacan-icon-viewminiature' : adminViewMode == 'grid',
|
||||||
'tainacan-icon-viewrecords' : adminViewMode == 'records',
|
'tainacan-icon-viewrecords' : adminViewMode == 'records',
|
||||||
'tainacan-icon-viewlist' : adminViewMode == 'list',
|
'tainacan-icon-viewlist' : adminViewMode == 'list',
|
||||||
'tainacan-icon-viewmasonry' : adminViewMode == 'masonry' }"
|
'tainacan-icon-viewmasonry' : adminViewMode == 'masonry' || adminViewMode == 'mosaic',
|
||||||
|
'tainacan-icon-rotate-90' : adminViewMode == 'mosaic'
|
||||||
|
}"
|
||||||
class="tainacan-icon tainacan-icon-1-25em" />
|
class="tainacan-icon tainacan-icon-1-25em" />
|
||||||
<svg
|
<svg
|
||||||
v-else
|
v-else
|
||||||
|
@ -426,6 +429,17 @@
|
||||||
</span>
|
</span>
|
||||||
<span>{{ $i18n.get('label_cards') }}</span>
|
<span>{{ $i18n.get('label_cards') }}</span>
|
||||||
</b-dropdown-item>
|
</b-dropdown-item>
|
||||||
|
<b-dropdown-item
|
||||||
|
aria-controls="items-list-results"
|
||||||
|
role="button"
|
||||||
|
:class="{ 'is-active': adminViewMode == 'mosaic' }"
|
||||||
|
:value="'mosaic'"
|
||||||
|
aria-role="listitem">
|
||||||
|
<span class="icon gray-icon">
|
||||||
|
<i class="tainacan-icon tainacan-icon-viewmasonry tainacan-icon-rotate-90" />
|
||||||
|
</span>
|
||||||
|
<span>{{ $i18n.get('label_mosaic') }}</span>
|
||||||
|
</b-dropdown-item>
|
||||||
<b-dropdown-item
|
<b-dropdown-item
|
||||||
v-if="!collection || (collection && collection.hide_items_thumbnail_on_lists != 'yes')"
|
v-if="!collection || (collection && collection.hide_items_thumbnail_on_lists != 'yes')"
|
||||||
aria-controls="items-list-results"
|
aria-controls="items-list-results"
|
||||||
|
@ -773,7 +787,7 @@
|
||||||
},
|
},
|
||||||
adminViewMode() {
|
adminViewMode() {
|
||||||
const currentAdminViewMode = this.getAdminViewMode();
|
const currentAdminViewMode = this.getAdminViewMode();
|
||||||
return ['table', 'cards', 'records', 'grid', 'masonry', 'list', 'map'].indexOf(currentAdminViewMode) >= 0 ? currentAdminViewMode : 'table';
|
return ['table', 'cards', 'records', 'grid', 'masonry', 'list', 'map', 'mosaic'].indexOf(currentAdminViewMode) >= 0 ? currentAdminViewMode : 'table';
|
||||||
},
|
},
|
||||||
orderByName() {
|
orderByName() {
|
||||||
const metadatumName = this.$orderByHelper.getOrderByMetadatumName({
|
const metadatumName = this.$orderByHelper.getOrderByMetadatumName({
|
||||||
|
@ -994,6 +1008,7 @@
|
||||||
existingViewMode == 'list' ||
|
existingViewMode == 'list' ||
|
||||||
existingViewMode == 'grid' ||
|
existingViewMode == 'grid' ||
|
||||||
existingViewMode == 'masonry'||
|
existingViewMode == 'masonry'||
|
||||||
|
existingViewMode == 'mosaic'||
|
||||||
existingViewMode == 'map')
|
existingViewMode == 'map')
|
||||||
this.$eventBusSearch.setInitialAdminViewMode(this.$userPrefs.get(prefsAdminViewMode));
|
this.$eventBusSearch.setInitialAdminViewMode(this.$userPrefs.get(prefsAdminViewMode));
|
||||||
else
|
else
|
||||||
|
|
|
@ -140,7 +140,7 @@
|
||||||
.metadata-title {
|
.metadata-title {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
padding: 0.6em 7em 0.5em 2.75em;
|
padding: 0.6em 7em 0.5em 2.75em;
|
||||||
min-height: 40px;
|
min-height: 1.5em;
|
||||||
position: relative;
|
position: relative;
|
||||||
font-size: 1em !important;
|
font-size: 1em !important;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
|
|
||||||
:deep(img) {
|
:deep(img) {
|
||||||
height: auto;
|
height: auto;
|
||||||
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
|
@ -111,7 +112,7 @@
|
||||||
.metadata-title {
|
.metadata-title {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
padding: 0.5em 7em 0.5em 2.75em;
|
padding: 0.5em 7em 0.5em 2.75em;
|
||||||
min-height: 40px;
|
min-height: 1.5em;
|
||||||
position: relative;
|
position: relative;
|
||||||
font-size: 1em !important;
|
font-size: 1em !important;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
|
|
@ -264,6 +264,7 @@
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
.metadata-title {
|
.metadata-title {
|
||||||
|
box-sizing: border-box;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
padding: 0.25em 1.125em;
|
padding: 0.25em 1.125em;
|
||||||
font-size: 1.0em !important;
|
font-size: 1.0em !important;
|
||||||
|
|
|
@ -110,6 +110,7 @@
|
||||||
|
|
||||||
:deep(img) {
|
:deep(img) {
|
||||||
height: auto;
|
height: auto;
|
||||||
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover:not(.skeleton) {
|
&:hover:not(.skeleton) {
|
||||||
|
@ -191,7 +192,7 @@
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
margin: 0px 6px 0px 24px;
|
margin: 0px 6px 0px 24px;
|
||||||
padding: 8px 1em;
|
padding: 8px 1em;
|
||||||
min-height: 41px;
|
min-height: calc(1em + 8px);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,221 @@
|
||||||
|
.tainacan-mosaic-container,
|
||||||
|
.tainacan-mosaic-container--skeleton {
|
||||||
|
--tainacan-mosaic-view-mode-gap: 12px;
|
||||||
|
--tainacan-mosaic-view-mode-min-height: 180px;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
grid-gap: calc(2em + 16px) var(--tainacan-mosaic-view-mode-gap, 12px);
|
||||||
|
list-style: none;
|
||||||
|
height: auto;
|
||||||
|
min-height: 0px; /* While most view modes set this to 50vh, this causes a bug for this one if there are few items to display */
|
||||||
|
margin: 0;
|
||||||
|
margin-bottom: calc(2em + 16px + var(--tainacan-container-padding));
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
animation-name: appear;
|
||||||
|
animation-duration: 0.5s;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: " ";
|
||||||
|
flex-grow: 1000000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > li,
|
||||||
|
& > .skeleton {
|
||||||
|
flex-grow: calc(var(--tainacan-mosaic-item-width, 300) * (100000 / var(--tainacan-mosaic-item-height, 300)));
|
||||||
|
flex-basis: calc(var(--tainacan-mosaic-view-mode-min-height, 180) * (var(--tainacan-mosaic-item-width, 300) / var(--tainacan-mosaic-item-height, 300)));
|
||||||
|
aspect-ratio: var(--tainacan-mosaic-item-width, 300) / var(--tainacan-mosaic-item-height, 300);
|
||||||
|
position: relative;
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
|
||||||
|
:deep(img) {
|
||||||
|
position: absolute;
|
||||||
|
width: auto;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(canvas.child) {
|
||||||
|
aspect-ratio: var(--tainacan-mosaic-item-width, 300) / var(--tainacan-mosaic-item-height, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover:not(.skeleton) {
|
||||||
|
background-color: var(--tainacan-item-heading-hover-background-color);
|
||||||
|
}
|
||||||
|
&.selected-mosaic-item:not(.skeleton) {
|
||||||
|
background-color: var(--tainacan-turquoise1);
|
||||||
|
}
|
||||||
|
&:not(.skeleton) {
|
||||||
|
background-color: var(--tainacan-item-background-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tainacan-mosaic-item {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mosaic-item-checkbox {
|
||||||
|
position: absolute;
|
||||||
|
margin-top: 8px;
|
||||||
|
margin-left: 1em;
|
||||||
|
z-index: 9;
|
||||||
|
}
|
||||||
|
.actions-area {
|
||||||
|
position: relative;
|
||||||
|
float: right;
|
||||||
|
width: 100%;
|
||||||
|
height: 0px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
visibility: hidden;
|
||||||
|
overflow: hidden;
|
||||||
|
opacity: 0.0;
|
||||||
|
padding: 8px;
|
||||||
|
margin-top: -25px;
|
||||||
|
background-color: var(--tainacan-item-heading-hover-background-color);
|
||||||
|
transition: visibility 0.2s ease, opacity 0.3s ease, height 0.2s ease, margin-top 0.1s ease;
|
||||||
|
|
||||||
|
a {
|
||||||
|
margin-left: 8px;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease-in;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:hover,
|
||||||
|
&:focus,
|
||||||
|
&:focus-within,
|
||||||
|
&:focus-visible,
|
||||||
|
& > a:focus,
|
||||||
|
& > a:focus-within,
|
||||||
|
& > a:focus-visible {
|
||||||
|
background: var(--tainacan-item-hover-background-color);
|
||||||
|
|
||||||
|
.actions-area {
|
||||||
|
visibility: visible;
|
||||||
|
opacity: 1.0;
|
||||||
|
height: 42px;
|
||||||
|
margin-top: 0px;
|
||||||
|
background-color: var(--tainacan-item-heading-hover-background-color);
|
||||||
|
|
||||||
|
a {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.selected-mosaic-item {
|
||||||
|
.actions-area {
|
||||||
|
background-color: var(--tainacan-turquoise1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tainacan-mosaic-item-thumbnail {
|
||||||
|
background-size: cover;
|
||||||
|
background-color: var(--tainacan-item-background-color);
|
||||||
|
background-blend-mode: multiply;
|
||||||
|
border-radius: 0px;
|
||||||
|
min-width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.metadata-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin: 0;
|
||||||
|
padding: 8px 1em;
|
||||||
|
min-height: calc(1em + 8px);
|
||||||
|
width: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 0.875em !important;
|
||||||
|
color: var(--tainacan-heading-color) !important;
|
||||||
|
text-align: left !important;
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
line-height: 1.5em;
|
||||||
|
word-break: break-word;
|
||||||
|
margin: 0;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slideshow-icon {
|
||||||
|
color: var(--tainacan-info-color);
|
||||||
|
position: absolute;
|
||||||
|
right: 5px;
|
||||||
|
top: 8px;
|
||||||
|
transform: scale(0.0);
|
||||||
|
transition: transform 0.2s ease;
|
||||||
|
}
|
||||||
|
.icon:not(.slideshow-icon) {
|
||||||
|
float: left;
|
||||||
|
margin-top: -1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus,
|
||||||
|
&:focus-within,
|
||||||
|
&:focus-visible,
|
||||||
|
& > a:focus,
|
||||||
|
& > a:focus-within,
|
||||||
|
& > a:focus-visible {
|
||||||
|
.metadata-title {
|
||||||
|
background: var(--tainacan-item-heading-hover-background-color);
|
||||||
|
|
||||||
|
.slideshow-icon {
|
||||||
|
transform: scale(1.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.hide-items-selection {
|
||||||
|
.tainacan-mosaic-item {
|
||||||
|
&:hover { background-color: transparent; cursor: default; }
|
||||||
|
&:hover .tainacan-mosaic-item-thumbnail { cursor: default; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.has-title-inside {
|
||||||
|
gap: var(--tainacan-mosaic-view-mode-gap, 12px);
|
||||||
|
|
||||||
|
& > li {
|
||||||
|
.metadata-title {
|
||||||
|
top: unset;
|
||||||
|
bottom: 0;
|
||||||
|
white-space: wrap;
|
||||||
|
overflow: visible;
|
||||||
|
text-overflow: none;
|
||||||
|
|
||||||
|
p {
|
||||||
|
white-space: wrap;
|
||||||
|
overflow: visible;
|
||||||
|
text-overflow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:not(:hover):not(:focus):not(:focus-within):not(:focus-visible),
|
||||||
|
& > a:not(:hover):not(:focus):not(:focus-within):not(:focus-visible) {
|
||||||
|
.metadata-title {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -75,6 +75,7 @@
|
||||||
|
|
||||||
:deep(img) {
|
:deep(img) {
|
||||||
height: auto;
|
height: auto;
|
||||||
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
|
@ -150,7 +151,7 @@
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
padding: 0.5em 7em 0.5em 2.75em;
|
padding: 0.5em 7em 0.5em 2.75em;
|
||||||
font-size: 1.0em !important;
|
font-size: 1.0em !important;
|
||||||
min-height: 40px;
|
min-height: 1.5em;
|
||||||
position: relative;
|
position: relative;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
|
@ -28,7 +28,7 @@ export default (element) => {
|
||||||
let registeredViewModes =
|
let registeredViewModes =
|
||||||
( tainacan_blocks && tainacan_blocks.registered_view_modes && tainacan_blocks.registered_view_modes.length ) ?
|
( tainacan_blocks && tainacan_blocks.registered_view_modes && tainacan_blocks.registered_view_modes.length ) ?
|
||||||
tainacan_blocks.registered_view_modes :
|
tainacan_blocks.registered_view_modes :
|
||||||
[ 'table', 'cards', 'records', 'masonry', 'list', 'map' ];
|
[ 'table', 'cards', 'records', 'masonry', 'mosaic', 'list', 'map'];
|
||||||
|
|
||||||
// At first, we consider that all registered view modes are included.
|
// At first, we consider that all registered view modes are included.
|
||||||
let possibleViewModes = registeredViewModes.filter((aViewMode) => aViewMode === 'slideshow');
|
let possibleViewModes = registeredViewModes.filter((aViewMode) => aViewMode === 'slideshow');
|
||||||
|
|
|
@ -0,0 +1,137 @@
|
||||||
|
<template>
|
||||||
|
<div class="table-container">
|
||||||
|
<div class="table-wrapper">
|
||||||
|
|
||||||
|
<!-- Empty result placeholder, rendered in the parent component -->
|
||||||
|
<slot />
|
||||||
|
|
||||||
|
<!-- SKELETON LOADING -->
|
||||||
|
<div
|
||||||
|
v-if="isLoading"
|
||||||
|
class="tainacan-mosaic-container--skeleton">
|
||||||
|
<div
|
||||||
|
v-for="item in 12"
|
||||||
|
:key="item"
|
||||||
|
:style="{
|
||||||
|
'--tainacan-mosaic-item-width': randomHeightForMosaicItem(),
|
||||||
|
'--tainacan-mosaic-item-height': randomHeightForMosaicItem()
|
||||||
|
}"
|
||||||
|
class="skeleton" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- MOSAIC VIEW MODE -->
|
||||||
|
<ul
|
||||||
|
v-if="!isLoading"
|
||||||
|
class="tainacan-mosaic-container">
|
||||||
|
<li
|
||||||
|
v-for="(item, index) of items"
|
||||||
|
:key="index"
|
||||||
|
:style="{
|
||||||
|
'--tainacan-mosaic-item-width': getAcceptableWidthBasedOnRatio(item['thumbnail'], 'tainacan-large-full', 300),
|
||||||
|
'--tainacan-mosaic-item-height': $thumbHelper.getHeight(item['thumbnail'], 'tainacan-large-full', 300)
|
||||||
|
}"
|
||||||
|
:data-tainacan-item-id="item.id"
|
||||||
|
:aria-setsize="totalItems"
|
||||||
|
:aria-posinset="getPosInSet(index)">
|
||||||
|
<a
|
||||||
|
|
||||||
|
class="tainacan-mosaic-item"
|
||||||
|
:href="getItemLink(item.url, index)">
|
||||||
|
|
||||||
|
<!-- JS-side hook for extra content -->
|
||||||
|
<div
|
||||||
|
v-if="hasBeforeHook()"
|
||||||
|
class="faceted-search-hook faceted-search-hook-item-before"
|
||||||
|
v-html="getBeforeHook(item)" />
|
||||||
|
|
||||||
|
<!-- Thumbnail -->
|
||||||
|
<blur-hash-image
|
||||||
|
v-if="item.thumbnail != undefined"
|
||||||
|
class="tainacan-mosaic-item-thumbnail"
|
||||||
|
:width="$thumbHelper.getWidth(item['thumbnail'], 'tainacan-large-full', 320)"
|
||||||
|
:height="$thumbHelper.getHeight(item['thumbnail'], 'tainacan-large-full', 320)"
|
||||||
|
:hash="$thumbHelper.getBlurhashString(item['thumbnail'], 'tainacan-large-full')"
|
||||||
|
:src="$thumbHelper.getSrc(item['thumbnail'], 'tainacan-large-full', item.document_mimetype)"
|
||||||
|
:srcset="$thumbHelper.getSrcSet(item['thumbnail'], 'tainacan-large-full', item.document_mimetype)"
|
||||||
|
:alt="item.thumbnail_alt ? item.thumbnail_alt : $i18n.get('label_thumbnail')"
|
||||||
|
:transition-duration="500"
|
||||||
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Title -->
|
||||||
|
<div
|
||||||
|
class="metadata-title"
|
||||||
|
:style="isSlideshowViewModeEnabled ? 'padding-right: 2rem;' : ''">
|
||||||
|
<p
|
||||||
|
v-tooltip="{
|
||||||
|
delay: {
|
||||||
|
show: 750,
|
||||||
|
hide: 100,
|
||||||
|
},
|
||||||
|
content: item.title != undefined ? item.title : '',
|
||||||
|
html: true,
|
||||||
|
placement: 'auto-start',
|
||||||
|
popperClass: ['tainacan-tooltip', 'tooltip']
|
||||||
|
}"
|
||||||
|
v-html="item.title != undefined ? item.title : ''" />
|
||||||
|
<span
|
||||||
|
v-if="isSlideshowViewModeEnabled"
|
||||||
|
v-tooltip="{
|
||||||
|
delay: {
|
||||||
|
show: 500,
|
||||||
|
hide: 100,
|
||||||
|
},
|
||||||
|
content: $i18n.get('label_see_on_fullscreen'),
|
||||||
|
placement: 'auto-start',
|
||||||
|
popperClass: ['tainacan-tooltip', 'tooltip']
|
||||||
|
}"
|
||||||
|
class="icon slideshow-icon"
|
||||||
|
@click.prevent="starSlideshowFromHere(index)">
|
||||||
|
<i class="tainacan-icon tainacan-icon-viewgallery tainacan-icon-1-125em" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- JS-side hook for extra content -->
|
||||||
|
<div
|
||||||
|
v-if="hasAfterHook()"
|
||||||
|
class="faceted-search-hook faceted-search-hook-item-after"
|
||||||
|
v-html="getAfterHook(item)" />
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { viewModesMixin } from '../js/view-modes-mixin.js';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ViewModeMosaic',
|
||||||
|
mixins: [
|
||||||
|
viewModesMixin
|
||||||
|
],
|
||||||
|
methods: {
|
||||||
|
randomHeightForMosaicItem() {
|
||||||
|
let min = 120;
|
||||||
|
let max = 280;
|
||||||
|
|
||||||
|
return Math.floor(Math.random()*(max-min+1)+min);
|
||||||
|
},
|
||||||
|
getAcceptableWidthBasedOnRatio(thumbnail, size, defaultSize) {
|
||||||
|
const width = this.$thumbHelper.getWidth(thumbnail, size, defaultSize);
|
||||||
|
const height = this.$thumbHelper.getHeight(thumbnail, size, defaultSize);
|
||||||
|
|
||||||
|
return (width / height) > 0.7 ? width : ( height * 0.7 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
@import "../../../../../admin/scss/_view-mode-mosaic.scss";
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
|
@ -179,6 +179,7 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 100% !important;
|
max-width: 100% !important;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filters-components-list {
|
.filters-components-list {
|
||||||
|
|
|
@ -77,7 +77,7 @@ export default (element) => {
|
||||||
const registeredViewModes =
|
const registeredViewModes =
|
||||||
( tainacan_plugin && tainacan_plugin.registered_view_modes && tainacan_plugin.registered_view_modes.length ) ?
|
( tainacan_plugin && tainacan_plugin.registered_view_modes && tainacan_plugin.registered_view_modes.length ) ?
|
||||||
tainacan_plugin.registered_view_modes :
|
tainacan_plugin.registered_view_modes :
|
||||||
[ 'table', 'cards', 'records', 'masonry', 'slideshow', 'list', 'map' ];
|
[ 'table', 'cards', 'records', 'masonry', 'mosaic', 'slideshow', 'list', 'map'];
|
||||||
|
|
||||||
// At first, we consider that all registered view modes are included.
|
// At first, we consider that all registered view modes are included.
|
||||||
let possibleViewModes = registeredViewModes;
|
let possibleViewModes = registeredViewModes;
|
||||||
|
|
|
@ -336,6 +336,7 @@ return apply_filters( 'tainacan-i18n', [
|
||||||
'label_grid' => __( 'Thumbnails', 'tainacan' ),
|
'label_grid' => __( 'Thumbnails', 'tainacan' ),
|
||||||
'label_table' => __( 'Table', 'tainacan' ),
|
'label_table' => __( 'Table', 'tainacan' ),
|
||||||
'label_cards' => __( 'Cards', 'tainacan' ),
|
'label_cards' => __( 'Cards', 'tainacan' ),
|
||||||
|
'label_mosaic' => __( 'Mosaic', 'tainacan' ),
|
||||||
/* translators: The 'records' view mode, in the sense of a catalog file */
|
/* translators: The 'records' view mode, in the sense of a catalog file */
|
||||||
'label_records' => __( 'Records', 'tainacan' ),
|
'label_records' => __( 'Records', 'tainacan' ),
|
||||||
'label_masonry' => __( 'Masonry', 'tainacan' ),
|
'label_masonry' => __( 'Masonry', 'tainacan' ),
|
||||||
|
|
Loading…
Reference in New Issue