Merge pull request #6294 from lasniscinote/gl_SCI_9354

Item card preload and section title animation[SCI-9354]
This commit is contained in:
Alex Kriuchykhin 2023-10-02 13:51:49 +02:00 committed by GitHub
commit f40e5a3c46
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 294 additions and 217 deletions

View file

@ -0,0 +1,11 @@
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1629_19712)">
<path d="M15.005 28.1194C11.5882 28.025 8.3431 26.6014 5.95975 24.1513C3.57641 21.7013 2.24294 18.4181 2.24294 15C2.24294 11.5819 3.57641 8.29872 5.95975 5.84865C8.3431 3.39859 11.5882 1.97498 15.005 1.88063V0C12.0373 0 9.13624 0.880028 6.66868 2.5288C4.20112 4.17757 2.27789 6.52103 1.14219 9.26284C0.00650146 12.0046 -0.290648 15.0216 0.288324 17.9323C0.867295 20.843 2.29638 23.5167 4.39487 25.6151C6.49336 27.7136 9.16699 29.1427 12.0777 29.7217C14.9884 30.3007 18.0054 30.0035 20.7472 28.8678C23.489 27.7321 25.8324 25.8089 27.4812 23.3413C29.13 20.8738 30.01 17.9727 30.01 15.005H28.1194C28.1141 18.4815 26.7307 21.8141 24.2724 24.2724C21.8141 26.7307 18.4815 28.1141 15.005 28.1194Z" fill="#EAECF0"/>
<path d="M15.005 0V1.88063C18.4833 1.88592 21.8174 3.27069 24.2759 5.73112C26.7345 8.19156 28.1167 11.5267 28.1194 15.005H30.01C30.01 11.0254 28.4291 7.20885 25.6151 4.39486C22.8012 1.58088 18.9846 0 15.005 0Z" fill="#1D2939"/>
</g>
<defs>
<clipPath id="clip0_1629_19712">
<rect width="30" height="30" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -7,7 +7,8 @@
e.stopPropagation();
e.preventDefault();
window.repositoryItemSidebarComponent.toggleShowHideSidebar($(this).attr('href'));
const repositoryRowURL = $(this).attr('href');
window.repositoryItemSidebarComponent.toggleShowHideSidebar(repositoryRowURL);
});
$(document).on('click', '.print-label-button', function(e) {

View file

@ -2,6 +2,7 @@
@import "tailwind/buttons";
@import "tailwind/modals";
@import "tailwind/flyouts";
@import "tailwind/loader.css";
@tailwind base;
@tailwind components;

View file

@ -0,0 +1,6 @@
@layer components {
.sci-loader {
@apply flex m-auto h-[30px] w-[30px] animate-spin;
background: image-url("sn-loader.svg") center center no-repeat;
}
}

View file

@ -1,161 +1,179 @@
<template>
<div id="repository-item-sidebar" class="w-ful h-full bg-white flex flex-col relative">
<div class="header fixed w-full">
<div class="flex justify-between m-6 h-[31px]">
<h4 class="my-auto truncate" :title="defaultColumns?.name">
{{ !defaultColumns?.archived ? i18n.t('labels.archived') : '' }}
{{ defaultColumns?.name }}
</h4>
<i @click="toggleShowHideSidebar" class="sn-icon sn-icon-close ml-auto cursor-pointer my-auto mx-0"></i>
<div ref="wrapper"
class='bg-white overflow-auto gap-2.5 self-stretch rounded-tl-4 rounded-bl-4 transition-transform ease-in-out transform shadow-lg'
:class="{ 'translate-x-0 w-[565px] h-full': isShowing, 'transition-transform ease-in-out duration-400 transform translate-x-0 translate-x-full': !isShowing }">
<div id="repository-item-sidebar" class="w-full h-full py-6 px-6 bg-white flex flex-col">
<div id="sticky-header-wrapper">
<div class="header flex w-full">
<h4 class="item-name my-auto truncate" :title="defaultColumns?.name">
{{ !defaultColumns?.archived ? i18n.t('labels.archived') : '' }}
{{ defaultColumns?.name }}
</h4>
<i id="close-icon" @click="toggleShowHideSidebar(currentItemUrl)"
class="sn-icon sn-icon-close ml-auto cursor-pointer my-auto mx-0"></i>
</div>
<div id="divider" class="flex w-500 bg-sn-light-grey my-6 self-stretch h-px items-center pt-px">
</div>
</div>
</div>
<div id="divider" class="bg-sn-sleepy-grey flex mt-[79px] mx-6 items-center self-stretch h-px"></div>
<div class="overflow-auto content flex flex-col justify-between px-6 h-full relative scroll-smooth">
<aside class="navigations fixed top-28 right-6">
<nav class="w-full">
<ul class="flex flex-col gap-3 text-right list-none">
<li v-for="nav in navigations" :key="nav.value" class="cursor-pointer inline-block relative">
<span :class="`${activeNav === nav.value ? 'text-sn-science-blue' : 'text-sn-grey'} mr-8 transition-colors`"
@click.prevent="hightlightContent(nav.value)">
{{ nav.label }}
</span>
<span
:class="`${activeNav === nav.value ? 'bg-sn-science-blue w-1 inset-y-0 right-0.5' : 'transparent hidden'} absolute transition-all rounded`">
</span>
</li>
</ul>
</nav>
</aside>
<div id="body-wrapper" class="grow-1">
<div class="flex flex-col gap-4 mb-4 mt-4 w-[350px]">
<section id="information_wrapper">
<h4 class="font-inter text-base font-semibold leading-7 mb-4">
{{ i18n.t('repositories.item_card.title.information') }}
</h4>
<div class="flex flex-col gap-4">
<div class="flex flex-col ">
<span class="inline-block font-semibold pb-[6px]">{{
i18n.t('repositories.item_card.default_columns.repository_name') }}</span>
<span class="text-sn-dark-grey line-clamp-3" :title="repositoryName">
{{ repositoryName }}
</span>
</div>
<div v-if="dataLoading" class="h-full flex flex-grow-1">
<div class="sci-loader"></div>
</div>
<div id="dashed-divider" class="flex h-[1px] py-0 border-dashed border-[1px] border-sn-light-grey"></div>
<div v-else id="body-wrapper" class="flex flex-1 flex-grow-1 justify-between">
<div id="left-col" class="flex flex-col gap-4">
<div class="flex flex-col ">
<span class="inline-block font-semibold pb-[6px]">{{ i18n.t('repositories.item_card.default_columns.id')
}}</span>
<span class="inline-block text-sn-dark-grey">
{{ defaultColumns?.code }}
</span>
</div>
<div id="dashed-divider" class="flex h-[1px] py-0 border-dashed border-[1px] border-sn-light-grey"></div>
<div class="flex flex-col ">
<span class="inline-block font-semibold pb-[6px]">{{
i18n.t('repositories.item_card.default_columns.added_on')
}}</span>
<span class="inline-block text-sn-dark-grey">
{{ defaultColumns?.added_on }}
</span>
</div>
<div id="dashed-divider" class="flex h-[1px] py-0 border-dashed border-[1px] border-sn-light-grey"></div>
<div class="flex flex-col ">
<span class="inline-block font-semibold pb-[6px]">{{
i18n.t('repositories.item_card.default_columns.added_by')
}}</span>
<span class="inline-block text-sn-dark-grey">
{{ defaultColumns?.added_by }}
</span>
</div>
<!-- INFORMATION -->
<div id="information">
<div ref="information-label" id="information-label"
class="font-inter text-base font-semibold leading-7 mb-4 transition-colors duration-300">{{
i18n.t('repositories.item_card.title.information') }}
</div>
</section>
<div id="divider" class="w-500 bg-sn-light-grey flex items-center self-stretch h-px "></div>
<section id="custom_columns_wrapper" class="flex flex-col min-h-[64px] h-auto">
<h4 id="custom-columns-label" class="font-inter text-base font-semibold leading-7 pb-4">
{{ i18n.t('repositories.item_card.navigations.custom_columns') }}
</h4>
<!-- start of custom columns -->
<div v-if="customColumns?.length > 0" class="flex flex-col gap-4 w-[350px] h-auto">
<div v-for="(column, index) in customColumns" class="flex flex-col gap-4 w-[350px] h-auto">
<component :is="column.data_type" :key="index" :data_type="column.data_type" :colId="column.id"
:colName="column.name" :colVal="column.value" />
<div id="dashed-divider" :class="{ 'hidden': index === customColumns.length - 1 }"
class="flex h-[1px] py-0 border-dashed border-[1px] border-sn-light-grey">
<div class="item-details">
<div class="flex flex-col gap-4">
<!-- REPOSITORY NAME -->
<div class="flex flex-col ">
<span class="inline-block font-semibold pb-[6px]">{{
i18n.t('repositories.item_card.default_columns.repository_name') }}</span>
<span class="repository-name flex text-sn-dark-grey" :title="repositoryName">
{{ repositoryName }}
</span>
</div>
<div id="dashed-divider" class="flex h-[1px] py-0 border-dashed border-[1px] border-sn-light-grey"></div>
<!-- CODE -->
<div class="flex flex-col ">
<span class="inline-block font-semibold pb-[6px]">{{ i18n.t('repositories.item_card.default_columns.id')
}}</span>
<span class="inline-block text-sn-dark-grey" :title="defaultColumns?.code">
{{ defaultColumns?.code }}
</span>
</div>
<div id="dashed-divider" class="flex h-[1px] py-0 border-dashed border-[1px] border-sn-light-grey"></div>
<!-- ADDED ON -->
<div class="flex flex-col ">
<span class="inline-block font-semibold pb-[6px]">{{
i18n.t('repositories.item_card.default_columns.added_on')
}}</span>
<span class="inline-block text-sn-dark-grey" :title="defaultColumns?.added_on">
{{ defaultColumns?.added_on }}
</span>
</div>
<div id="dashed-divider" class="flex h-[1px] py-0 border-dashed border-[1px] border-sn-light-grey"></div>
<!-- ADDED BY -->
<div class="flex flex-col ">
<span class="inline-block font-semibold pb-[6px]">{{
i18n.t('repositories.item_card.default_columns.added_by')
}}</span>
<span class="inline-block text-sn-dark-grey" :title="defaultColumns?.added_by">
{{ defaultColumns?.added_by }}
</span>
</div>
</div>
</div>
<!-- end of custom columns -->
<div v-else id="custom-columns-value" class="text-sn-dark-grey font-inter text-sm font-normal leading-5">
{{ i18n.t('repositories.item_card.no_custom_columns_label') }}
</div>
</section>
</div>
<div id="divider" class="w-500 bg-sn-light-grey flex px-8 items-center self-stretch h-px "></div>
<div id="divider" class="w-500 bg-sn-light-grey flex items-center self-stretch h-px "></div>
<section id="assigned_wrapper" class="flex flex-col ">
<div class="text-base font-semibold w-[350px] my-3 leading-7">
{{ i18n.t('repositories.item_card.section.assigned', { count: assignedModules ? assignedModules.total_assigned_size : 0 }) }}
</div>
<div v-if="assignedModules && assignedModules.total_assigned_size > 0">
<div v-if="privateModuleSize() > 0" class="pb-6">
{{ i18n.t('repositories.item_card.assigned.private', { count: privateModuleSize() }) }}
<hr v-if="assignedModules.viewable_modules.length > 0"
class="h-1 w-[350px] m-0 mt-6 border-dashed border-1 border-sn-light-grey"/>
<!-- CUSTOM COLUMNS, ASSIGNED, QR CODE -->
<div id="custom-col-assigned-qr-wrapper" class="flex flex-col gap-4">
<!-- CUSTOM COLUMNS -->
<div id="custom-columns-wrapper" class="flex flex-col min-h-[64px] h-auto">
<div ref="custom-columns-label" id="custom-columns-label"
class="font-inter text-base font-semibold leading-7 pb-4 transition-colors duration-300">
{{ i18n.t('repositories.item_card.custom_columns_label') }}
</div>
<div v-for="(assigned, index) in assignedModules.viewable_modules"
:key="`assigned_module_${index}`"
class="flex flex-col w-[350px] mb-6 h-auto">
<div class="flex flex-col gap-3">
<div v-for="(item, index_assigned) in assigned"
:key="`assigned_element_${index_assigned}`">
{{ i18n.t(`repositories.item_card.assigned.labels.${item.type}`) }}
<a :href="item.url">
{{ item.archived ? i18n.t('labels.archived') : '' }} {{ item.value }}
</a>
<div v-if="customColumns?.length > 0" class="flex flex-col gap-4 w-[350px] h-auto">
<div v-for="(column, index) in customColumns" class="flex flex-col gap-4 w-[350px] h-auto">
<component :is="column.data_type" :key="index" :data_type="column.data_type" :colId="column.id"
:colName="column.name" :colVal="column.value" />
<div id="dashed-divider" :class="{ 'hidden': index === customColumns.length - 1 }"
class="flex h-[1px] py-0 border-dashed border-[1px] border-sn-light-grey">
</div>
</div>
<hr v-if="index < assignedModules.viewable_modules.length - 1"
class="h-1 w-[350px] mt-6 mb-0 border-dashed border-1 border-sn-light-grey"/>
</div>
<div v-else class="text-sn-dark-grey font-inter text-sm font-normal leading-5">
{{ i18n.t('repositories.item_card.no_custom_columns_label') }}
</div>
</div>
<div v-else class="mb-3">
{{ i18n.t('repositories.item_card.assigned.empty') }}
</div>
</section>
<div id="divider" class="w-500 bg-sn-light-grey flex px-8 items-center self-stretch h-px "></div>
<div id="divider" class="w-500 bg-sn-light-grey flex px-8 items-center self-stretch h-px"></div>
<section id="qr_wrapper">
<h4 class="font-inter text-base font-semibold leading-7 mb-4 mt-0">{{
i18n.t('repositories.item_card.navigations.qr') }}</h4>
<div class="bar-code-container">
<canvas id="bar-code-canvas" class="hidden"></canvas>
<img id="bar-code-image" />
<!-- ASSIGNED -->
<section id="assigned_wrapper" class="flex flex-col ">
<div class="text-base font-semibold w-[350px] my-3 leading-7" ref="assigned-label">
{{ i18n.t('repositories.item_card.section.assigned', {
count: assignedModules ?
assignedModules.total_assigned_size : 0
}) }}
</div>
<div v-if="assignedModules && assignedModules.total_assigned_size > 0">
<div v-if="privateModuleSize() > 0" class="pb-6">
{{ i18n.t('repositories.item_card.assigned.private', { count: privateModuleSize() }) }}
<hr v-if="assignedModules.viewable_modules.length > 0"
class="h-1 w-[350px] m-0 mt-6 border-dashed border-1 border-sn-light-grey" />
</div>
<div v-for="(assigned, index) in assignedModules.viewable_modules" :key="`assigned_module_${index}`"
class="flex flex-col w-[350px] mb-6 h-auto">
<div class="flex flex-col gap-3">
<div v-for="(item, index_assigned) in assigned" :key="`assigned_element_${index_assigned}`">
{{ i18n.t(`repositories.item_card.assigned.labels.${item.type}`) }}
<a :href="item.url">
{{ item.archived ? i18n.t('labels.archived') : '' }} {{ item.value }}
</a>
</div>
</div>
<hr v-if="index < assignedModules.viewable_modules.length - 1"
class="h-1 w-[350px] mt-6 mb-0 border-dashed border-1 border-sn-light-grey" />
</div>
</div>
<div v-else class="mb-3">
{{ i18n.t('repositories.item_card.assigned.empty') }}
</div>
</section>
<div id="divider" class="w-500 bg-sn-light-grey flex px-8 items-center self-stretch h-px "></div>
<!-- QR -->
<div id="QR-wrapper" class="block">
<div ref="QR-label" id="QR-label"
class="font-inter text-base font-semibold leading-7 mb-4 transition-colors duration-300">QR</div>
<canvas id="bar-code-canvas" class="hidden" data-id="IT2"></canvas>
<img :src="barCodeSrc" />
</div>
</section>
</div>
</div>
<!-- NAVIGATION -->
<div id="navigation" class="flex item-end gap-x-4 min-w-[130px] h-[130px] sticky top-0 right-0">
<scroll-spy :itemsToCreate="[
{ id: 'highlight-item-1', textId: 'text-item-1', labelAlias: 'information_label', label: 'information-label' },
{ id: 'highlight-item-2', textId: 'text-item-2', labelAlias: 'custom_columns_label', label: 'custom-columns-label' },
{ id: 'highlight-item-3', textId: 'text-item-3', labelAlias: 'assigned_label', label: 'assigned-label' },
{ id: 'highlight-item-4', textId: 'text-item-4', labelAlias: 'QR_label', label: 'QR-label' }
]">
</scroll-spy>
</div>
</div>
<div class="footer">
<div id="divider" class="w-full bg-sn-sleepy-grey flex items-center self-stretch h-px mb-6"></div>
<div id="bottom-button-wrapper" class="flex mb-6 justify-end">
<button type="button" class="btn btn-primary print-label-button" :data-rows="JSON.stringify([repositoryRowId])">
{{ i18n.t('repository_row.modal_print_label.print_label') }}
</button>
<!-- BOTTOM -->
<div id="bottom" class="h-[100px] flex flex-col justify-end" :class="{ 'pb-6': customColumns?.length }">
<div id="divider" class="w-500 bg-sn-light-grey flex px-8 items-center self-stretch h-px mb-6"></div>
<div id="bottom-button-wrapper" class="flex h-10 justify-end">
<button class="btn btn-primary">Print Label</button>
</div>
</div>
</div>
</div>
</template>
@ -174,6 +192,7 @@ import RepositoryDateValue from './repository_values/RepositoryDateValue.vue';
import RepositoryDateRangeValue from './repository_values/RepositoryDateRangeValue.vue';
import RepositoryTimeRangeValue from './repository_values/RepositoryTimeRangeValue.vue'
import RepositoryTimeValue from './repository_values/RepositoryTimeValue.vue'
import ScrollSpy from './repository_values/ScrollSpy.vue';
export default {
name: 'RepositoryItemSidebar',
@ -190,19 +209,19 @@ export default {
RepositoryDateValue,
RepositoryDateRangeValue,
RepositoryTimeRangeValue,
RepositoryTimeValue
RepositoryTimeValue,
'scroll-spy': ScrollSpy
},
data() {
return {
repositoryRowId: null,
currentItemUrl: null,
dataLoading: false,
repositoryName: null,
defaultColumns: null,
customColumns: null,
assignedModules: null,
isShowing: false,
navClicked: false,
activeNav: 'information',
sequenceExpanded: false,
assigned: 'Assigned to 3 private tasks that will not be displayed',
barCodeSrc: null
}
},
@ -210,98 +229,59 @@ export default {
window.repositoryItemSidebarComponent = this;
},
watch: {
isShowing(newVal, oldVal) {
const element = document.getElementById('repositoryItemSidebar')
if (this.isShowing) {
element.classList.remove('translate-x-full');
element.classList.add('translate-x-0');
} else {
element.classList.add('transition-transform', 'ease-in-out', 'duration-300', 'transform', 'translate-x-0', 'translate-x-full');
defaultColumns(newCol, oldCol) {
const canvasEl = document.getElementById('bar-code-canvas')
if (newCol.code && bwipjs && canvasEl) {
// generate the QR code
let barCodeCanvas = bwipjs.toCanvas('bar-code-canvas', {
bcid: 'qrcode',
text: newCol.code,
scale: 3
});
this.barCodeSrc = barCodeCanvas.toDataURL('image/png')
}
}
},
computed: {
navigations() {
return ['information', 'custom_columns', 'assigned', 'qr'].map(nav => (
{ label: I18n.t(`repositories.item_card.navigations.${nav}`), value: nav }
));
}
},
},
beforeDestroy() {
delete window.repositoryItemSidebarComponent;
},
methods: {
toggleShowHideSidebar(repositoryRowUrl) {
this.isShowing = !this.isShowing
this.loadRepositoryRow(repositoryRowUrl);
},
toggleExpandSequence() {
if (this.sequenceExpanded) {
document.getElementById('sequence-container').classList.remove('h-fit', 'max-h-[600px]')
document.getElementById('sequence-container').classList.add('h-[60px]')
} else {
document.getElementById('sequence-container').classList.remove('h-[60px]')
document.getElementById('sequence-container').classList.add('h-fit', 'max-h-[600px]')
// initial click
if (this.currentItemUrl === null) {
this.isShowing = true
this.loadRepositoryRow(repositoryRowUrl)
this.currentItemUrl = repositoryRowUrl
return
}
// click on the same item - should just open/close it
else if (this.currentItemUrl === repositoryRowUrl) {
this.isShowing = false
this.currentItemUrl = null
return
}
// click on a different item - should just fetch new data
else {
this.loadRepositoryRow(repositoryRowUrl)
this.currentItemUrl = repositoryRowUrl
return
}
this.sequenceExpanded = !this.sequenceExpanded
},
loadRepositoryRow(repositoryRowUrl) {
this.dataLoading = true
$.ajax({
method: 'GET',
url: repositoryRowUrl,
dataType: 'json',
success: (result) => {
this.repositoryRowId = result.id;
this.repositoryName = result.repository_name;
this.defaultColumns = result.default_columns;
this.customColumns = result.custom_columns;
this.dataLoading = false
this.assignedModules = result.assigned_modules;
this.$nextTick(() => {
this.generateBarCode(this.defaultColumns.code);
this.attachScrollEvent();
});
}
});
},
hightlightContent(nav) {
this.activeNav = nav;
this.navClicked = true;
this.$nextTick(function () {
$(`#repository-item-sidebar #${nav}_wrapper`)[0].scrollIntoView();
})
},
attachScrollEvent() {
const topOffsets = {}
const sections = ['information', 'custom_columns', 'assigned', 'qr'];
for (let idx = 0; idx < sections.length; idx++) {
topOffsets[sections[idx]] = $(`#repository-item-sidebar #${sections[idx]}_wrapper`).offset().top;
}
let isScrolling;
$('.content').on('scroll', () => {
if (isScrolling !== null) clearTimeout(isScrolling);
isScrolling = setTimeout(() => {
const scrollPosition = $('.content').scrollTop();
for (let idx = 0; idx < sections.length; idx++) {
if (scrollPosition < topOffsets[sections[idx + 1]] - topOffsets['information']) {
// Set nav only when scrolling is not triggered by ckicking nav
if (sections[idx] !== this.activeNav && !this.navClicked) this.activeNav = sections[idx];
break;
}
}
this.navClicked = false;
}, 150)
})
},
generateBarCode(text) {
if (!text) return;
const barCodeCanvas = bwipjs.toCanvas('bar-code-canvas', {
bcid: 'qrcode',
text,
scale: 3
});
$('#repository-item-sidebar #bar-code-image').attr('src', barCodeCanvas.toDataURL('image/png'));
},
privateModuleSize() {
return this.assignedModules.total_assigned_size - this.assignedModules.viewable_modules.length;
}

View file

@ -15,7 +15,7 @@
</div>
</div>
<div v-else
class="text-sn-dark-grey font-inter text-sm font-normal leading-5 h-12 overflow-auto grid auto-rows-auto grid-cols-3">
class="text-sn-dark-grey font-inter text-sm font-normal leading-5 h-fit overflow-auto grid auto-rows-auto grid-cols-3">
<div v-for="(checklistItem, index) in allChecklistItems" :key="index">
<div id="checklist-item" class="min-w-max">
{{ `${checklistItem.label} |` }}

View file

@ -0,0 +1,76 @@
<template>
<div class="flex gap-3">
<div id="navigation-text">
<div class="flex flex-col py-2 px-0 gap-3 self-stretch w-[130px] h-[130px] justify-center items-center">
<div v-for="(itemObj, index) in itemsToCreate" :key="index"
class="flex flex-col w-[130px] h-[130px] justify-between text-right">
<div @click="handleSideNavClick" :id="itemObj?.textId" class="hover:cursor-pointer text-sn-grey"
:class="{ 'text-sn-science-blue': selectedNavText === itemObj?.textId }">{{
i18n.t(`repositories.highlight_component.${itemObj?.labelAlias}`) }}
</div>
</div>
</div>
</div>
<div id="highlight-container" class="w-[1px] h-[130px] flex flex-col justify-evenly bg-sn-light-grey">
<div v-for="(itemObj, index) in itemsToCreate" :key="index">
<div :id="itemObj.id" class="w-[5px] h-[28px] rounded-[11px]"
:class="{ 'bg-sn-science-blue relative left-[-2px]': itemObj.id === selectedNavIndicator }"></div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'ScrollSpy',
props: {
itemsToCreate: Array,
},
data() {
return {
rootContainerEl: null,
selectedNavText: null,
selectedNavIndicator: null
}
},
created() {
this.rootContainerEl = this.$parent.$refs.wrapper
},
methods: {
handleSideNavClick(e) {
if (!this.rootContainerEl) {
return
}
let refToScrollTo
const targetId = e.target.id
const foundObj = this.itemsToCreate.find((obj) => obj.textId === targetId)
if (!foundObj) return
refToScrollTo = foundObj.label
this.selectedNavText = foundObj.textId
this.selectedNavIndicator = foundObj.id
const sectionLabels = this.itemsToCreate.map((obj) => obj.label)
const labelsToUnhighlight = sectionLabels.filter((i) => i !== refToScrollTo)
// scrolling to desired section
const domElToScrollTo = this.$parent.$refs[refToScrollTo]
this.rootContainerEl.scrollTo({
top: domElToScrollTo.offsetTop,
behavior: "smooth"
})
// flashing the title color to blue and back over 300ms
const timeoutId = setTimeout(() => {
// wrapped in timeout to ensure that the color-change animation happens after the scrolling animation is completed
domElToScrollTo?.classList.add('text-sn-science-blue')
labelsToUnhighlight.forEach(id => document.getElementById(id)?.classList.remove('text-sn-science-blue'))
setTimeout(() => {
domElToScrollTo?.classList.remove('text-sn-science-blue')
}, 400)
clearTimeout(timeoutId)
}, 500)
}
}
}
</script>

View file

@ -1,6 +1,7 @@
<div
id="repositoryItemSidebar"
data-behaviour="vue"
class='bg-white fixed top-0 right-0 h-screen w-[565px] z-[9999] rounded-tl-4 rounded-bl-4 transition-transform ease-in-out transform translate-x-full'>
class="fixed top-0 right-0 h-full z-[9999]"
>
<repository-item-sidebar />
</div>

View file

@ -2227,12 +2227,8 @@ en:
id: "Item ID"
added_on: "Added on"
added_at: "Added at"
added_by: "Added by"
navigations:
information: "Information"
custom_columns: "Custom columns"
assigned: "Assigned"
qr: "QR"
added_by: 'Added by'
custom_columns_label: 'Custom columns'
no_custom_columns_label: 'This item has no custom columns'
repository_time_range_value:
no_time_range: 'No time range'
@ -2260,6 +2256,11 @@ en:
no_asset: 'No file'
repository_time_value:
no_time: 'No time'
highlight_component:
information_label: 'Information'
custom_columns_label: 'Custom columns'
assigned_label: 'Assigned'
QR_label: 'QR'
repository_stock_values:
manage_modal:
title: "Stock %{item}"