Working on new behaviour for switching between item clicks [SCI-9354]

Working on scrolling and highlighting [SCI-9354]

Item card preload and section title animation [SCI-9354]

Added box-shadow [SCI-9354]

Refactored logic and styles [SCI-9354]

PR fix, added back the missing HighlightComponent [SCI-9354]

PR fixes, refactoring [SCI-9354]

PR fix [SCI-9354]

Fixed scrolling to 'Assigned', highlighting [SCI-9354]

PR fix, modular logic, rename [SCI-9354]
This commit is contained in:
Gregor Lasnibat 2023-09-22 16:08:43 +02:00
parent ba5ef94764
commit f352c7f186
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.stopPropagation();
e.preventDefault(); 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) { $(document).on('click', '.print-label-button', function(e) {

View file

@ -2,6 +2,7 @@
@import "tailwind/buttons"; @import "tailwind/buttons";
@import "tailwind/modals"; @import "tailwind/modals";
@import "tailwind/flyouts"; @import "tailwind/flyouts";
@import "tailwind/loader.css";
@tailwind base; @tailwind base;
@tailwind components; @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> <template>
<div id="repository-item-sidebar" class="w-ful h-full bg-white flex flex-col relative"> <div ref="wrapper"
<div class="header fixed w-full"> class='bg-white overflow-auto gap-2.5 self-stretch rounded-tl-4 rounded-bl-4 transition-transform ease-in-out transform shadow-lg'
<div class="flex justify-between m-6 h-[31px]"> :class="{ 'translate-x-0 w-[565px] h-full': isShowing, 'transition-transform ease-in-out duration-400 transform translate-x-0 translate-x-full': !isShowing }">
<h4 class="my-auto truncate" :title="defaultColumns?.name">
{{ !defaultColumns?.archived ? i18n.t('labels.archived') : '' }} <div id="repository-item-sidebar" class="w-full h-full py-6 px-6 bg-white flex flex-col">
{{ defaultColumns?.name }}
</h4> <div id="sticky-header-wrapper">
<i @click="toggleShowHideSidebar" class="sn-icon sn-icon-close ml-auto cursor-pointer my-auto mx-0"></i> <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>
<div id="divider" class="bg-sn-sleepy-grey flex mt-[79px] mx-6 items-center self-stretch h-px"></div> <div v-if="dataLoading" class="h-full flex flex-grow-1">
<div class="overflow-auto content flex flex-col justify-between px-6 h-full relative scroll-smooth"> <div class="sci-loader"></div>
<aside class="navigations fixed top-28 right-6"> </div>
<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 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 "> <!-- INFORMATION -->
<span class="inline-block font-semibold pb-[6px]">{{ i18n.t('repositories.item_card.default_columns.id') <div id="information">
}}</span> <div ref="information-label" id="information-label"
<span class="inline-block text-sn-dark-grey"> class="font-inter text-base font-semibold leading-7 mb-4 transition-colors duration-300">{{
{{ defaultColumns?.code }} i18n.t('repositories.item_card.title.information') }}
</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>
</div> </div>
</section> <div class="item-details">
<div class="flex flex-col gap-4">
<div id="divider" class="w-500 bg-sn-light-grey flex items-center self-stretch h-px "></div> <!-- REPOSITORY NAME -->
<div class="flex flex-col ">
<section id="custom_columns_wrapper" class="flex flex-col min-h-[64px] h-auto"> <span class="inline-block font-semibold pb-[6px]">{{
<h4 id="custom-columns-label" class="font-inter text-base font-semibold leading-7 pb-4"> i18n.t('repositories.item_card.default_columns.repository_name') }}</span>
{{ i18n.t('repositories.item_card.navigations.custom_columns') }} <span class="repository-name flex text-sn-dark-grey" :title="repositoryName">
</h4> {{ repositoryName }}
<!-- start of custom columns --> </span>
<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>
<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>
</div> </div>
<!-- end of custom columns --> </div>
<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 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 "> <!-- CUSTOM COLUMNS, ASSIGNED, QR CODE -->
<div class="text-base font-semibold w-[350px] my-3 leading-7"> <div id="custom-col-assigned-qr-wrapper" class="flex flex-col gap-4">
{{ i18n.t('repositories.item_card.section.assigned', { count: assignedModules ? assignedModules.total_assigned_size : 0 }) }}
</div> <!-- CUSTOM COLUMNS -->
<div v-if="assignedModules && assignedModules.total_assigned_size > 0"> <div id="custom-columns-wrapper" class="flex flex-col min-h-[64px] h-auto">
<div v-if="privateModuleSize() > 0" class="pb-6"> <div ref="custom-columns-label" id="custom-columns-label"
{{ i18n.t('repositories.item_card.assigned.private', { count: privateModuleSize() }) }} class="font-inter text-base font-semibold leading-7 pb-4 transition-colors duration-300">
<hr v-if="assignedModules.viewable_modules.length > 0" {{ i18n.t('repositories.item_card.custom_columns_label') }}
class="h-1 w-[350px] m-0 mt-6 border-dashed border-1 border-sn-light-grey"/>
</div> </div>
<div v-for="(assigned, index) in assignedModules.viewable_modules" <div v-if="customColumns?.length > 0" class="flex flex-col gap-4 w-[350px] h-auto">
:key="`assigned_module_${index}`" <div v-for="(column, index) in customColumns" class="flex flex-col gap-4 w-[350px] h-auto">
class="flex flex-col w-[350px] mb-6 h-auto"> <component :is="column.data_type" :key="index" :data_type="column.data_type" :colId="column.id"
<div class="flex flex-col gap-3"> :colName="column.name" :colVal="column.value" />
<div v-for="(item, index_assigned) in assigned" <div id="dashed-divider" :class="{ 'hidden': index === customColumns.length - 1 }"
:key="`assigned_element_${index_assigned}`"> class="flex h-[1px] py-0 border-dashed border-[1px] border-sn-light-grey">
{{ i18n.t(`repositories.item_card.assigned.labels.${item.type}`) }}
<a :href="item.url">
{{ item.archived ? i18n.t('labels.archived') : '' }} {{ item.value }}
</a>
</div> </div>
</div> </div>
<hr v-if="index < assignedModules.viewable_modules.length - 1" </div>
class="h-1 w-[350px] mt-6 mb-0 border-dashed border-1 border-sn-light-grey"/> <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> </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"> <!-- ASSIGNED -->
<h4 class="font-inter text-base font-semibold leading-7 mb-4 mt-0">{{ <section id="assigned_wrapper" class="flex flex-col ">
i18n.t('repositories.item_card.navigations.qr') }}</h4> <div class="text-base font-semibold w-[350px] my-3 leading-7" ref="assigned-label">
<div class="bar-code-container"> {{ i18n.t('repositories.item_card.section.assigned', {
<canvas id="bar-code-canvas" class="hidden"></canvas> count: assignedModules ?
<img id="bar-code-image" /> 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> </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> </div>
<div class="footer"> <!-- BOTTOM -->
<div id="divider" class="w-full bg-sn-sleepy-grey flex items-center self-stretch h-px mb-6"></div> <div id="bottom" class="h-[100px] flex flex-col justify-end" :class="{ 'pb-6': customColumns?.length }">
<div id="bottom-button-wrapper" class="flex mb-6 justify-end"> <div id="divider" class="w-500 bg-sn-light-grey flex px-8 items-center self-stretch h-px mb-6"></div>
<button type="button" class="btn btn-primary print-label-button" :data-rows="JSON.stringify([repositoryRowId])"> <div id="bottom-button-wrapper" class="flex h-10 justify-end">
{{ i18n.t('repository_row.modal_print_label.print_label') }} <button class="btn btn-primary">Print Label</button>
</button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
@ -174,6 +192,7 @@ import RepositoryDateValue from './repository_values/RepositoryDateValue.vue';
import RepositoryDateRangeValue from './repository_values/RepositoryDateRangeValue.vue'; import RepositoryDateRangeValue from './repository_values/RepositoryDateRangeValue.vue';
import RepositoryTimeRangeValue from './repository_values/RepositoryTimeRangeValue.vue' import RepositoryTimeRangeValue from './repository_values/RepositoryTimeRangeValue.vue'
import RepositoryTimeValue from './repository_values/RepositoryTimeValue.vue' import RepositoryTimeValue from './repository_values/RepositoryTimeValue.vue'
import ScrollSpy from './repository_values/ScrollSpy.vue';
export default { export default {
name: 'RepositoryItemSidebar', name: 'RepositoryItemSidebar',
@ -190,19 +209,19 @@ export default {
RepositoryDateValue, RepositoryDateValue,
RepositoryDateRangeValue, RepositoryDateRangeValue,
RepositoryTimeRangeValue, RepositoryTimeRangeValue,
RepositoryTimeValue RepositoryTimeValue,
'scroll-spy': ScrollSpy
}, },
data() { data() {
return { return {
repositoryRowId: null, currentItemUrl: null,
dataLoading: false,
repositoryName: null, repositoryName: null,
defaultColumns: null, defaultColumns: null,
customColumns: null, customColumns: null,
assignedModules: null, assignedModules: null,
isShowing: false, isShowing: false,
navClicked: false, assigned: 'Assigned to 3 private tasks that will not be displayed',
activeNav: 'information',
sequenceExpanded: false,
barCodeSrc: null barCodeSrc: null
} }
}, },
@ -210,98 +229,59 @@ export default {
window.repositoryItemSidebarComponent = this; window.repositoryItemSidebarComponent = this;
}, },
watch: { watch: {
isShowing(newVal, oldVal) { defaultColumns(newCol, oldCol) {
const element = document.getElementById('repositoryItemSidebar') const canvasEl = document.getElementById('bar-code-canvas')
if (this.isShowing) { if (newCol.code && bwipjs && canvasEl) {
element.classList.remove('translate-x-full'); // generate the QR code
element.classList.add('translate-x-0'); let barCodeCanvas = bwipjs.toCanvas('bar-code-canvas', {
} else { bcid: 'qrcode',
element.classList.add('transition-transform', 'ease-in-out', 'duration-300', 'transform', 'translate-x-0', 'translate-x-full'); 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() { beforeDestroy() {
delete window.repositoryItemSidebarComponent; delete window.repositoryItemSidebarComponent;
}, },
methods: { methods: {
toggleShowHideSidebar(repositoryRowUrl) { toggleShowHideSidebar(repositoryRowUrl) {
this.isShowing = !this.isShowing // initial click
this.loadRepositoryRow(repositoryRowUrl); if (this.currentItemUrl === null) {
}, this.isShowing = true
toggleExpandSequence() { this.loadRepositoryRow(repositoryRowUrl)
if (this.sequenceExpanded) { this.currentItemUrl = repositoryRowUrl
document.getElementById('sequence-container').classList.remove('h-fit', 'max-h-[600px]') return
document.getElementById('sequence-container').classList.add('h-[60px]') }
} else { // click on the same item - should just open/close it
document.getElementById('sequence-container').classList.remove('h-[60px]') else if (this.currentItemUrl === repositoryRowUrl) {
document.getElementById('sequence-container').classList.add('h-fit', 'max-h-[600px]') 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) { loadRepositoryRow(repositoryRowUrl) {
this.dataLoading = true
$.ajax({ $.ajax({
method: 'GET', method: 'GET',
url: repositoryRowUrl, url: repositoryRowUrl,
dataType: 'json', dataType: 'json',
success: (result) => { success: (result) => {
this.repositoryRowId = result.id;
this.repositoryName = result.repository_name; this.repositoryName = result.repository_name;
this.defaultColumns = result.default_columns; this.defaultColumns = result.default_columns;
this.customColumns = result.custom_columns; this.customColumns = result.custom_columns;
this.dataLoading = false
this.assignedModules = result.assigned_modules; 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() { privateModuleSize() {
return this.assignedModules.total_assigned_size - this.assignedModules.viewable_modules.length; return this.assignedModules.total_assigned_size - this.assignedModules.viewable_modules.length;
} }

View file

@ -15,7 +15,7 @@
</div> </div>
</div> </div>
<div v-else <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 v-for="(checklistItem, index) in allChecklistItems" :key="index">
<div id="checklist-item" class="min-w-max"> <div id="checklist-item" class="min-w-max">
{{ `${checklistItem.label} |` }} {{ `${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 <div
id="repositoryItemSidebar" id="repositoryItemSidebar"
data-behaviour="vue" 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 /> <repository-item-sidebar />
</div> </div>

View file

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