mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-09-10 15:14:33 +08:00
Merge pull request #6445 from sboursen-scinote/sb_SCI-9527
Fix item card scroller [SCI-9527]
This commit is contained in:
commit
45699fdced
2 changed files with 175 additions and 177 deletions
|
@ -1,12 +1,12 @@
|
|||
<template>
|
||||
<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='items-sidebar-wrapper bg-white 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 w-0': !isShowing }">
|
||||
|
||||
<div id="repository-item-sidebar" class="w-full h-auto pb-6 px-6 bg-white flex flex-col">
|
||||
<div id="repository-item-sidebar" class="w-full h-full pl-6 bg-white flex flex-col">
|
||||
|
||||
<div id="sticky-header-wrapper" class="sticky top-0 right-0 bg-white flex z-50 flex-col h-[102px] pt-6">
|
||||
<div class="header flex w-full h-[30px]">
|
||||
<div id="sticky-header-wrapper" class="sticky top-0 right-0 bg-white flex z-50 flex-col h-[78px] pt-6">
|
||||
<div class="header flex w-full h-[30px] pr-6">
|
||||
<h4 class="item-name my-auto truncate" :title="defaultColumns?.name">
|
||||
{{ defaultColumns?.archived ? i18n.t('labels.archived') : '' }}
|
||||
{{ defaultColumns?.name }}
|
||||
|
@ -15,180 +15,183 @@
|
|||
class="sn-icon sn-icon-close ml-auto cursor-pointer my-auto mx-0"></i>
|
||||
</div>
|
||||
|
||||
<div id="divider" class="w-500 bg-sn-light-grey flex items-center self-stretch h-px my-6"></div>
|
||||
<div id="divider" class="w-500 bg-sn-light-grey flex items-center self-stretch h-px mt-6"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div v-if="dataLoading" class="h-full flex flex-grow-1">
|
||||
<div class="sci-loader"></div>
|
||||
</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 ref="bodyWrapper" id="body-wrapper" class="overflow-auto h-[calc(100%-78px)] pt-6">
|
||||
<div v-if="dataLoading" class="h-full flex flex-grow-1">
|
||||
<div class="sci-loader"></div>
|
||||
</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.section.information') }}
|
||||
</div>
|
||||
<div>
|
||||
<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="repository?.name">
|
||||
{{ repository?.name }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-else class="flex flex-1 flex-grow-1 justify-between">
|
||||
<div id="left-col" class="flex flex-col gap-4">
|
||||
|
||||
<div class="sci-divider"></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 class="sci-divider"></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 class="sci-divider"></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>
|
||||
<!-- 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.section.information') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="divider" class="w-500 bg-sn-light-grey flex items-center self-stretch h-px "></div>
|
||||
|
||||
<!-- 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-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 relative">
|
||||
<span class="absolute right-2 top-6" v-if="column?.value?.reminder === true">
|
||||
<Reminder :value="column?.value" :valueType="column?.value_type" />
|
||||
</span>
|
||||
|
||||
<component :is="column.data_type" :key="index" :data_type="column.data_type" :colId="column.id"
|
||||
:colName="column.name" :colVal="column.value" :repositoryRowId="repositoryRowId"
|
||||
:repositoryId="repository.id"
|
||||
:permissions="permissions" @closeSidebar="toggleShowHideSidebar(null)" />
|
||||
|
||||
<div class="sci-divider" :class="{ 'hidden': index === customColumns?.length - 1 }"></div>
|
||||
|
||||
</div>
|
||||
</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 id="divider" class="w-500 bg-sn-light-grey flex px-8 items-center self-stretch h-px"></div>
|
||||
|
||||
<!-- ASSIGNED -->
|
||||
<section id="assigned_wrapper" class="flex flex-col">
|
||||
<div class="flex flex-row text-base font-semibold w-[350px] pb-4 leading-7 items-center justify-between" ref="assigned-label">
|
||||
{{ i18n.t('repositories.item_card.section.assigned', {
|
||||
count: assignedModules ?
|
||||
assignedModules.total_assigned_size : 0
|
||||
}) }}
|
||||
<a v-if="actions?.assign_repository_row || (inRepository && !defaultColumns?.archived)"
|
||||
class="btn-text-link font-normal"
|
||||
:class= "{'assign-inventory-button': actions?.assign_repository_row,
|
||||
'disabled': actions?.assign_repository_row && actions.assign_repository_row.disabled }"
|
||||
:data-assign-url="actions?.assign_repository_row ? actions.assign_repository_row.assign_url : ''"
|
||||
:data-repository-row-id="repositoryRowId"
|
||||
@click="showRepositoryAssignModal">
|
||||
{{ i18n.t('repositories.item_card.assigned.assign') }}
|
||||
</a>
|
||||
</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" class="text-sn-science-blue">
|
||||
{{ item.archived ? i18n.t('labels.archived') : '' }} {{ item.value }}
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<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="repository?.name">
|
||||
{{ repository?.name }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="sci-divider"></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 class="sci-divider"></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 class="sci-divider"></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>
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
||||
<!-- QR -->
|
||||
<section id="qr-wrapper" ref="QR-label">
|
||||
<div class="font-inter text-base font-semibold leading-7 mb-4 mt-0">{{ i18n.t('repositories.item_card.section.qr') }}</div>
|
||||
<div class="bar-code-container">
|
||||
<canvas id="bar-code-canvas" class="hidden"></canvas>
|
||||
<img :src="barCodeSrc" />
|
||||
<!-- 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-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 relative">
|
||||
<span class="absolute right-2 top-6" v-if="column?.value?.reminder === true">
|
||||
<Reminder :value="column?.value" :valueType="column?.value_type" />
|
||||
</span>
|
||||
|
||||
<component :is="column.data_type" :key="index" :data_type="column.data_type" :colId="column.id"
|
||||
:colName="column.name" :colVal="column.value" :repositoryRowId="repositoryRowId"
|
||||
:repositoryId="repository.id"
|
||||
:permissions="permissions" @closeSidebar="toggleShowHideSidebar(null)" />
|
||||
|
||||
<div class="sci-divider" :class="{ 'hidden': index === customColumns?.length - 1 }"></div>
|
||||
|
||||
</div>
|
||||
</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>
|
||||
</section>
|
||||
|
||||
<div id="divider" class="w-500 bg-sn-light-grey flex px-8 items-center self-stretch h-px"></div>
|
||||
|
||||
<!-- ASSIGNED -->
|
||||
<section id="assigned_wrapper" class="flex flex-col">
|
||||
<div class="flex flex-row text-base font-semibold w-[350px] pb-4 leading-7 items-center justify-between" ref="assigned-label">
|
||||
{{ i18n.t('repositories.item_card.section.assigned', {
|
||||
count: assignedModules ?
|
||||
assignedModules.total_assigned_size : 0
|
||||
}) }}
|
||||
<a v-if="actions?.assign_repository_row || (inRepository && !defaultColumns?.archived)"
|
||||
class="btn-text-link font-normal"
|
||||
:class= "{'assign-inventory-button': actions?.assign_repository_row,
|
||||
'disabled': actions?.assign_repository_row && actions.assign_repository_row.disabled }"
|
||||
:data-assign-url="actions?.assign_repository_row ? actions.assign_repository_row.assign_url : ''"
|
||||
:data-repository-row-id="repositoryRowId"
|
||||
@click="showRepositoryAssignModal">
|
||||
{{ i18n.t('repositories.item_card.assigned.assign') }}
|
||||
</a>
|
||||
</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" class="text-sn-science-blue">
|
||||
{{ 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 -->
|
||||
<section id="qr-wrapper" ref="QR-label">
|
||||
<div class="font-inter text-base font-semibold leading-7 mb-4 mt-0">{{ i18n.t('repositories.item_card.section.qr') }}</div>
|
||||
<div class="bar-code-container">
|
||||
<canvas id="bar-code-canvas" class="hidden"></canvas>
|
||||
<img :src="barCodeSrc" />
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- NAVIGATION -->
|
||||
<div ref="navigationRef" id="navigation"
|
||||
class="flex item-end gap-x-4 min-w-[130px] min-h-[130px] h-fit absolute top-[102px] right-[24px] ">
|
||||
<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' }
|
||||
]" :stickyHeaderHeightPx="102" :cardTopPaddingPx="null" v-show="isShowing">
|
||||
</scroll-spy>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- NAVIGATION -->
|
||||
<div ref="navigationRef" id="navigation"
|
||||
class="flex item-end gap-x-4 min-w-[130px] min-h-[130px] h-fit absolute top-[102px] right-[24px] ">
|
||||
<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' }
|
||||
]" :stickyHeaderHeightPx="102" :cardTopPaddingPx="null">
|
||||
</scroll-spy>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- BOTTOM -->
|
||||
<div id="bottom" class="h-[100px] flex flex-col justify-end mt-4" :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 type="button" class="btn btn-primary print-label-button" :data-rows="JSON.stringify([repositoryRowId])">
|
||||
{{ i18n.t('repositories.item_card.print_label') }}
|
||||
</button>
|
||||
<!-- BOTTOM -->
|
||||
<div id="bottom" class="h-[100px] flex flex-col justify-end mt-4" :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 type="button" class="btn btn-primary print-label-button" :data-rows="JSON.stringify([repositoryRowId])">
|
||||
{{ i18n.t('repositories.item_card.print_label') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -31,32 +31,27 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
rootContainerEl: null,
|
||||
bodyContainerEl: null,
|
||||
selectedNavText: null,
|
||||
selectedNavIndicator: null,
|
||||
positions: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.rootContainerEl = this.$parent.$refs.wrapper
|
||||
this.rootContainerEl?.addEventListener('scroll', this.handleScrollBehaviour)
|
||||
this.bodyContainerEl = this.$parent.$refs.bodyWrapper
|
||||
this.bodyContainerEl?.addEventListener('scroll', this.updateNavigationPositionOnScroll)
|
||||
},
|
||||
|
||||
methods: {
|
||||
handleScrollBehaviour() {
|
||||
// used for keeping scroll spy sticky
|
||||
this.updateNavigationPositionOnScroll()
|
||||
},
|
||||
updateNavigationPositionOnScroll() {
|
||||
updateNavigationPositionOnScroll(e) {
|
||||
const navigationDom = this?.$parent?.$refs?.navigationRef
|
||||
// Get the current scroll position
|
||||
const scrollPosition = this?.rootContainerEl?.scrollTop
|
||||
const scrollPosition = this?.bodyContainerEl?.scrollTop
|
||||
// Adjust navigationDom position equal to the scrollPosition + the header height and the card top padding (if present)
|
||||
navigationDom.style.top = `${scrollPosition + this?.stickyHeaderHeightPx + this?.cardTopPaddingPx}px`;
|
||||
// navigationDom.style.top = `${scrollPosition + this?.stickyHeaderHeightPx + this?.cardTopPaddingPx}px`;
|
||||
},
|
||||
|
||||
handleSideNavClick(e) {
|
||||
if (!this.rootContainerEl) {
|
||||
if (!this.bodyContainerEl) {
|
||||
return
|
||||
}
|
||||
let refToScrollTo
|
||||
|
@ -70,11 +65,11 @@ export default {
|
|||
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 - this?.stickyHeaderHeightPx - this?.cardTopPaddingPx,
|
||||
const top = domElToScrollTo.offsetTop - this?.stickyHeaderHeightPx - this?.cardTopPaddingPx;
|
||||
this.bodyContainerEl.scrollTo({
|
||||
top: top,
|
||||
behavior: "auto"
|
||||
})
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue