mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-09-05 20:54:27 +08:00
Make navigator resizable [SCI-9318]
This commit is contained in:
parent
957f539e32
commit
d34d424b0f
7 changed files with 87 additions and 26 deletions
|
@ -10,7 +10,6 @@ body.navigator-collapsed {
|
|||
--breadcrumbs-navigation-height: 44px;
|
||||
--left-navigation-width: 192px;
|
||||
--navbar-height: calc(var(--top-navigation-height) + var(--breadcrumbs-navigation-height));
|
||||
--navigator-navigation-width: 224px;
|
||||
--title-row-height: 4em;
|
||||
--top-navigation-height: 72px;
|
||||
display: grid;
|
||||
|
@ -108,6 +107,11 @@ body.navigator-collapsed {
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
.resizable-r {
|
||||
cursor: url("/images/icon_small/Resize.svg") 0 0, auto !important;
|
||||
padding: 0 .8rem;
|
||||
}
|
||||
}
|
||||
|
||||
.w-98 {
|
||||
|
|
|
@ -20,6 +20,9 @@ class NavigationsController < ApplicationController
|
|||
|
||||
def navigator_state
|
||||
session[:navigator_collapsed] = params[:state] == 'collapsed'
|
||||
|
||||
width = params[:width].to_i
|
||||
session[:navigator_width] = width if width.positive?
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -1,34 +1,49 @@
|
|||
<template>
|
||||
<div class="w-[208px] ml-4 h-full border rounded relative bg-sn-white flex flex-col right-0 absolute navigator-container">
|
||||
<div class="px-3 py-2.5 flex items-center relative leading-4">
|
||||
<i class="sn-icon sn-icon-navigator"></i>
|
||||
<div class="font-bold text-base pl-3">
|
||||
{{ i18n.t('navigator.title') }}
|
||||
<vue-resizable
|
||||
ref="vueResizable"
|
||||
:max-width="600"
|
||||
:min-width="208"
|
||||
width="auto"
|
||||
height="100%"
|
||||
:active="['r']"
|
||||
@resize:start="onResizeStart"
|
||||
@resize:move="onResizeMove"
|
||||
@resize:end="onResizeEnd"
|
||||
>
|
||||
<div class="ml-4 h-full border rounded relative bg-sn-white flex flex-col right-0 absolute navigator-container">
|
||||
<div class="px-3 py-2.5 flex items-center relative leading-4">
|
||||
<i class="sn-icon sn-icon-navigator"></i>
|
||||
<div class="font-bold text-base pl-3">
|
||||
{{ i18n.t('navigator.title') }}
|
||||
</div>
|
||||
<i @click="$emit('navigator:colapse')" class="sn-icon sn-icon-close ml-auto cursor-pointer absolute right-2.5 top-2.5"></i>
|
||||
</div>
|
||||
<i @click="$emit('navigator:colapse')" class="sn-icon sn-icon-close ml-auto cursor-pointer absolute right-2.5 top-2.5"></i>
|
||||
<perfect-scrollbar @ps-scroll-y="onScrollY" @ps-scroll-x="onScrollX" ref="scrollContainer" class="grow py-2 relative px-2 scroll-container">
|
||||
<NavigatorItem v-for="item in sortedMenuItems"
|
||||
:key="item.id"
|
||||
:currentItemId="currentItemId"
|
||||
:item="item"
|
||||
:firstLevel="true"
|
||||
:reloadCurrentLevel="reloadCurrentLevel"
|
||||
:paddingLeft="0"
|
||||
:reloadChildrenLevel="reloadChildrenLevel"
|
||||
:archived="archived" />
|
||||
</perfect-scrollbar>
|
||||
</div>
|
||||
<perfect-scrollbar @ps-scroll-y="onScrollY" @ps-scroll-x="onScrollX" ref="scrollContainer" class="grow py-2 relative px-2 scroll-container">
|
||||
<NavigatorItem v-for="item in sortedMenuItems"
|
||||
:key="item.id"
|
||||
:currentItemId="currentItemId"
|
||||
:item="item"
|
||||
:firstLevel="true"
|
||||
:reloadCurrentLevel="reloadCurrentLevel"
|
||||
:paddingLeft="0"
|
||||
:reloadChildrenLevel="reloadChildrenLevel"
|
||||
:archived="archived" />
|
||||
</perfect-scrollbar>
|
||||
</div>
|
||||
</vue-resizable>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import NavigatorItem from './navigator_item.vue'
|
||||
import VueResizable from 'vue-resizable'
|
||||
import axios from '../../packs/custom_axios.js';
|
||||
|
||||
export default {
|
||||
name : 'NavigatorContainer',
|
||||
components: {
|
||||
NavigatorItem
|
||||
NavigatorItem,
|
||||
VueResizable
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -70,6 +85,9 @@ export default {
|
|||
}
|
||||
});
|
||||
},
|
||||
mounted() {
|
||||
this.$refs.vueResizable.style.width = this.getNavigatorWidth()
|
||||
},
|
||||
watch: {
|
||||
archived() {
|
||||
this.loadTree();
|
||||
|
@ -89,21 +107,50 @@ export default {
|
|||
this.currentItemId = $('#active_navigator_item').val();
|
||||
this.archived = $('#active_navigator_archived').val() === 'true';
|
||||
},
|
||||
loadTree() {
|
||||
async loadTree() {
|
||||
if (!this.navigatorUrl) return;
|
||||
|
||||
$.get(this.navigatorUrl, {archived: this.archived}, (data) => {
|
||||
this.menuItems = [];
|
||||
this.$nextTick(() => {
|
||||
this.menuItems = data.items;
|
||||
try {
|
||||
const { data } = await axios.get(this.navigatorUrl, {
|
||||
params: { archived: this.archived }
|
||||
});
|
||||
})
|
||||
this.menuItems = data.items;
|
||||
} catch (error) {
|
||||
console.error('An error occurred while fetching the data', error);
|
||||
}
|
||||
},
|
||||
onScrollY({target}) {
|
||||
this.navigatorYScroll = target.scrollTop;
|
||||
},
|
||||
onScrollX({target}) {
|
||||
this.navigatorXScroll = target.scrollLeft;
|
||||
},
|
||||
getNavigatorWidth() {
|
||||
const computedStyle = getComputedStyle(document.documentElement);
|
||||
return computedStyle.getPropertyValue('--navigator-navigation-width').trim();
|
||||
},
|
||||
onResizeMove(event) {
|
||||
document.documentElement.style.setProperty('--navigator-navigation-width', event.width + 'px');
|
||||
},
|
||||
onResizeStart() {
|
||||
document.body.style.cursor = 'url(/images/icon_small/Resize.svg) 0 0, auto';
|
||||
$('.sci--layout-navigation-navigator').addClass('no-transition');
|
||||
$('.sci--layout').addClass('no-transition');
|
||||
},
|
||||
onResizeEnd(event) {
|
||||
document.body.style.cursor = 'default';
|
||||
$('.sci--layout-navigation-navigator').removeClass('no-transition');
|
||||
$('.sci--layout').removeClass('no-transition');
|
||||
this.changeNavigatorState(event.width)
|
||||
},
|
||||
async changeNavigatorState(newWidth) {
|
||||
try {
|
||||
const navigatorContainer = document.getElementById('sciNavigationNavigatorContainer');
|
||||
const stateUrl = navigatorContainer.getAttribute('data-navigator-state-url');
|
||||
await axios.post(stateUrl, { width: newWidth });
|
||||
} catch (error) {
|
||||
console.error('An error occurred while sending the request', error);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
<%= stylesheet_link_tag 'tui_image_editor_styles' %>
|
||||
<%= javascript_include_tag 'vue_navigation_navigator' %>
|
||||
<%= javascript_include_tag 'vue_navigation_top_menu' %>
|
||||
<style> :root { --navigator-navigation-width: <%= session[:navigator_width] || Constants::DEFAULT_NAV_WIDTH %>px; } </style>
|
||||
</head>
|
||||
<body
|
||||
class="<%= yield :body_class %> <%= 'navigator-collapsed' if !@navigator || session[:navigator_collapsed] %> <%= 'w-[98%]' if params[:controller] == 'label_templates' && params[:action] == 'show'%>"
|
||||
|
|
|
@ -73,6 +73,8 @@ class Constants
|
|||
EXPERIMENT_LONG_DESCRIPTION = 80
|
||||
# Infinite scroll default elements per page
|
||||
DEFAULT_ELEMENTS_PER_PAGE = 20
|
||||
# Default navigator width
|
||||
DEFAULT_NAV_WIDTH = 208
|
||||
|
||||
#=============================================================================
|
||||
# File and data memory size
|
||||
|
|
|
@ -78,6 +78,7 @@
|
|||
"twemoji": "^12.1.4",
|
||||
"vue": "^2.6.11",
|
||||
"vue-loader": "^15.9.1",
|
||||
"vue-resizable": "2.1.3",
|
||||
"vue-template-compiler": "^2.6.12",
|
||||
"vue-turbolinks": "^2.2.1",
|
||||
"vue2-perfect-scrollbar": "^1.5.56",
|
||||
|
|
3
public/images/icon_small/Resize.svg
Normal file
3
public/images/icon_small/Resize.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg width="25.33" height="10" viewBox="0 0 25.33 10" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14.51 0.320059L13.81 1.02006L17.1 4.31006H9H8.77H1.9L5.2 1.01006L4.5 0.310059L0 4.81006L4.5 9.31006L5.2 8.61006L1.9 5.31006H8.77H9H17.1L13.8 8.61006L14.5 9.31006L19 4.81006L14.51 0.320059Z" fill="#1D2939"/>
|
||||
</svg>
|
After Width: | Height: | Size: 326 B |
Loading…
Add table
Reference in a new issue