mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-10-06 11:57:16 +08:00
Add sticky scrolling to task page [SCI-8980]
This commit is contained in:
parent
bbffce5e03
commit
6a287fa54f
6 changed files with 91 additions and 14 deletions
|
@ -345,7 +345,6 @@ function initProtocolSectionOpenEvent() {
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes page
|
||||
*/
|
||||
|
|
|
@ -115,7 +115,7 @@
|
|||
.task-section-header {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
min-height: 4rem;
|
||||
|
||||
.actions-block {
|
||||
display: flex;
|
||||
|
|
|
@ -1,15 +1,25 @@
|
|||
<template>
|
||||
<div v-if="protocol.id" class="task-protocol">
|
||||
<div class="task-section-header" v-if="!inRepository">
|
||||
<div class="portocol-header-left-part">
|
||||
<a class="task-section-caret" tabindex="0" role="button" data-toggle="collapse" href="#protocol-content" aria-expanded="true" aria-controls="protocol-content">
|
||||
<i class="sn-icon sn-icon-right"></i>
|
||||
<div class="task-section-title">
|
||||
<h2>{{ i18n.t('Protocol') }}</h2>
|
||||
<div ref="header" class="task-section-header ml-[-1rem] w-[calc(100%_+_2rem)] px-4 z-[250] bg-sn-white sticky top-0 transition" v-if="!inRepository">
|
||||
<div class="portocol-header-left-part truncate grow">
|
||||
<template v-if="headerSticked && protocol.attributes.assignable_my_module_name">
|
||||
<i class="sn-icon sn-icon-navigator sci--layout--navigator-open cursor-pointer p-1.5 border rounded border-sn-light-grey mr-4"></i>
|
||||
<div @click="scrollTop" class="task-section-title w-[calc(100%_-_4rem)] cursor-pointer">
|
||||
<h2 class="truncate">{{ protocol.attributes.assignable_my_module_name }}</h2>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else >
|
||||
<a class="task-section-caret" tabindex="0" role="button" data-toggle="collapse" href="#protocol-content" aria-expanded="true" aria-controls="protocol-content">
|
||||
<i class="sn-icon sn-icon-right"></i>
|
||||
<div class="task-section-title">
|
||||
<h2>{{ i18n.t('Protocol') }}</h2>
|
||||
</div>
|
||||
</a>
|
||||
</template>
|
||||
<div :class="{'hidden': headerSticked}" >
|
||||
<div class="my-module-protocol-status">
|
||||
<!-- protocol status dropdown gets mounted here -->
|
||||
</div>
|
||||
</a>
|
||||
<div class="my-module-protocol-status">
|
||||
<!-- protocol status dropdown gets mounted here -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions-block">
|
||||
|
@ -205,6 +215,8 @@
|
|||
reordering: false,
|
||||
publishing: false,
|
||||
stepToReload: null,
|
||||
headerSticked: false,
|
||||
lastScrollTop: 0,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
@ -212,12 +224,20 @@
|
|||
this.protocol = result.data;
|
||||
this.$nextTick(() => {
|
||||
this.refreshProtocolStatus();
|
||||
if (!this.inRepository) {
|
||||
window.addEventListener('scroll', this.initStackableHeaders, false);
|
||||
}
|
||||
});
|
||||
$.get(this.urls.steps_url, (result) => {
|
||||
this.steps = result.data
|
||||
})
|
||||
});
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (!this.inRepository) {
|
||||
window.removeEventListener('scroll', this.initStackableHeaders, false);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
reloadStep(step) {
|
||||
this.stepToReload = step;
|
||||
|
@ -363,6 +383,58 @@
|
|||
publishProtocol(comment) {
|
||||
this.protocol.attributes.version_comment = comment;
|
||||
$.post(this.urls.publish_url, {version_comment: comment, view: 'show'})
|
||||
},
|
||||
scrollTop() {
|
||||
window.scrollTo(0, 0);
|
||||
setTimeout(() => {
|
||||
$('.my_module-name .view-mode').trigger('click');
|
||||
$('.my_module-name .input-field').focus();
|
||||
}, 300)
|
||||
},
|
||||
initStackableHeaders() {
|
||||
let protocolHeader = this.$refs.header;
|
||||
let secondaryNavigation = document.querySelector('#taskSecondaryMenu');
|
||||
let protocolHeaderHeight = protocolHeader.offsetHeight;
|
||||
let protocolHeaderTop = protocolHeader.getBoundingClientRect().top;
|
||||
let secondaryNavigationHeight = secondaryNavigation.offsetHeight;
|
||||
let secondaryNavigationTop = secondaryNavigation.getBoundingClientRect().top;
|
||||
|
||||
// Add shadow to secondary navigation when it starts fly
|
||||
if (secondaryNavigation.getBoundingClientRect().top == 0 && !this.headerSticked) {
|
||||
secondaryNavigation.style.boxShadow = '0px 5px 8px 0px rgba(0, 0, 0, 0.10)';
|
||||
} else {
|
||||
secondaryNavigation.style.boxShadow = 'none';
|
||||
}
|
||||
|
||||
if (protocolHeaderTop < protocolHeaderHeight) { // When secondary navigation touch protocol header
|
||||
secondaryNavigation.style.top = protocolHeaderTop - protocolHeaderHeight + 'px'; // Secondary navigation starts slowly disappear
|
||||
protocolHeader.style.boxShadow = '0px 5px 8px 0px rgba(0, 0, 0, 0.10)'; // Flying shadow
|
||||
this.headerSticked = true;
|
||||
|
||||
|
||||
if (this.lastScrollTop > window.scrollY) { // When user scroll up
|
||||
let newSecondaryTop = secondaryNavigationTop - (window.scrollY - this.lastScrollTop); // Calculate new top position of secondary navigation
|
||||
if (newSecondaryTop > 0) newSecondaryTop = 0;
|
||||
|
||||
secondaryNavigation.style.top = newSecondaryTop + 'px'; // Secondary navigation starts slowly appear
|
||||
protocolHeader.style.top = secondaryNavigationHeight + newSecondaryTop - 1 + 'px'; // Protocol header starts getting offset to compensate secondary navigation position
|
||||
// -1 to compensate small gap between protocol header and secondary navigation
|
||||
} else { // When user scroll down
|
||||
let newSecondaryTop = secondaryNavigationTop - (window.scrollY - this.lastScrollTop); // Calculate new top position of secondary navigation
|
||||
if (newSecondaryTop * -1 > secondaryNavigationHeight ) newSecondaryTop = secondaryNavigationHeight * -1;
|
||||
|
||||
secondaryNavigation.style.top = newSecondaryTop + 'px'; // Secondary navigation starts slowly disappear
|
||||
protocolHeader.style.top = newSecondaryTop + secondaryNavigationHeight - 1 + 'px'; // Protocol header starts getting offset to compensate secondary navigation position
|
||||
// -1 to compensate small gap between protocol header and secondary navigation
|
||||
}
|
||||
} else {
|
||||
// Just reset secondary navigation and protocol header styles to initial state
|
||||
secondaryNavigation.style.top = '0px';
|
||||
protocolHeader.style.boxShadow = 'none';
|
||||
this.headerSticked = false;
|
||||
}
|
||||
|
||||
this.lastScrollTop = window.scrollY; // Save last scroll position to when user scroll up/down
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ class ProtocolSerializer < ActiveModel::Serializer
|
|||
attributes :name, :id, :urls, :description, :description_view, :updated_at, :in_repository,
|
||||
:created_at_formatted, :updated_at_formatted, :added_by, :authors, :keywords, :version,
|
||||
:code, :published, :version_comment, :archived, :linked, :has_draft,
|
||||
:published_on_formatted, :published_by, :created_from_version, :assignable_my_module_id
|
||||
:published_on_formatted, :published_by, :created_from_version, :assignable_my_module_id, :assignable_my_module_name
|
||||
|
||||
def updated_at
|
||||
object.updated_at.to_i
|
||||
|
@ -122,6 +122,12 @@ class ProtocolSerializer < ActiveModel::Serializer
|
|||
object.my_module&.id
|
||||
end
|
||||
|
||||
def assignable_my_module_name
|
||||
return if in_repository
|
||||
|
||||
object.my_module&.name
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_from_repo_url
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="content-header sticky-header my-module-header">
|
||||
<div class="content-header my-module-header">
|
||||
<div class="my-module-title-row title-row">
|
||||
<i class="sn-icon sn-icon-navigator sci--layout--navigator-open cursor-pointer p-1.5 border rounded border-sn-light-grey mr-4"></i>
|
||||
<h1 class="my_module-name" data-toggle="tooltip" data-placement="bottom" title="<%= @my_module.name %>">
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="bg-sn-white border-b border-solid border-0 border-sn-sleepy-grey rounded-t px-4 py-2">
|
||||
<div id="taskSecondaryMenu" class="bg-sn-white border-b border-solid border-0 border-sn-sleepy-grey rounded-t px-4 py-2 top-0 sticky z-[251]">
|
||||
<div class="flex items-center gap-4">
|
||||
<% if can_read_experiment?(@my_module.experiment) %>
|
||||
<a class="p-3 border-b-4 border-transparent hover:no-underline uppercase text-bold capitalize <%= is_module_protocols? ? "text-sn-blue" : "text-sn-grey" %>"
|
||||
|
|
Loading…
Add table
Reference in a new issue