@nextcloud/vue
Version:
Nextcloud vue components
301 lines (300 loc) • 10.4 kB
JavaScript
import '../assets/NcAppContent-DVBVZyuW.css';
import NcButton from "../Components/NcButton.mjs";
import { r as register, D as t26, a as t } from "./_l10n-JYjUKekn.mjs";
import "../Directives/Tooltip.mjs";
import { emit } from "@nextcloud/event-bus";
import { A as ArrowRight } from "./ArrowRight-KsL2PC-o.mjs";
import { useIsMobile } from "../Composables/useIsMobile.mjs";
import { n as normalizeComponent } from "./_plugin-vue2_normalizer-DU4iP6Vu.mjs";
import { VTooltip } from "floating-vue";
import { getBuilder } from "@nextcloud/browser-storage";
import { useSwipe } from "@vueuse/core";
import { Pane, Splitpanes } from "splitpanes";
import "splitpanes/dist/splitpanes.css";
register(t26);
const _sfc_main$1 = {
name: "NcAppDetailsToggle",
directives: {
tooltip: VTooltip
},
components: {
NcButton,
ArrowRight
},
setup() {
return {
isMobile: useIsMobile()
};
},
computed: {
title() {
return t("Go back to the list");
}
},
watch: {
isMobile: {
immediate: true,
handler() {
this.toggleAppNavigationButton(this.isMobile);
}
}
},
beforeDestroy() {
if (this.isMobile) {
this.toggleAppNavigationButton(false);
}
},
methods: {
toggleAppNavigationButton(hide = true) {
const appNavigationToggle = document.querySelector(".app-navigation .app-navigation-toggle");
if (appNavigationToggle) {
appNavigationToggle.style.display = hide ? "none" : null;
if (hide === true) {
emit("toggle-navigation", { open: false });
}
}
}
}
};
var _sfc_render$1 = function render() {
var _vm = this, _c = _vm._self._c;
return _c("NcButton", { directives: [{ name: "tooltip", rawName: "v-tooltip", value: _vm.title, expression: "title" }], staticClass: "app-details-toggle", class: { "app-details-toggle--mobile": _vm.isMobile }, attrs: { "type": "tertiary", "aria-label": _vm.title }, scopedSlots: _vm._u([{ key: "icon", fn: function() {
return [_c("ArrowRight", { attrs: { "size": 20 } })];
}, proxy: true }]) });
};
var _sfc_staticRenderFns$1 = [];
var __component__$1 = /* @__PURE__ */ normalizeComponent(
_sfc_main$1,
_sfc_render$1,
_sfc_staticRenderFns$1,
false,
null,
"7692fc78"
);
const NcAppDetailsToggle = __component__$1.exports;
const browserStorage = getBuilder("nextcloud").persist().build();
const _sfc_main = {
name: "NcAppContent",
components: {
NcAppDetailsToggle,
Pane,
Splitpanes
},
props: {
/**
* Allows to disable the control by swipe of the app navigation open state
*/
allowSwipeNavigation: {
type: Boolean,
default: true
},
/**
* Allows you to set the default width of the resizable list in % on vertical-split
* Allows you to set the default height of the resizable list in % on horizontal-split
* Must be between listMinWidth and listMaxWidth
*/
listSize: {
type: Number,
default: 20
},
/**
* Allows you to set the minimum width of the list column in % on vertical-split
* Allows you to set the minimum height of the list column in % on horizontal-split
*/
listMinWidth: {
type: Number,
default: 15
},
/**
* Allows you to set the maximum width of the list column in % on vertical-split
* Allows you to set the maximum height of the list column in % on horizontal-split
*/
listMaxWidth: {
type: Number,
default: 40
},
/**
* Specify the config key for the pane config sizes
* Default is the global var appName if you use the webpack-vue-config
*/
paneConfigKey: {
type: String,
default: ""
},
/**
* When in mobile view, only the list or the details are shown
* If you provide a list, you need to provide a variable
* that will be set to true by the user when an element of
* the list gets selected. The details will then show a back
* arrow to return to the list that will update this prop to false.
*/
showDetails: {
type: Boolean,
default: true
},
/**
* Specify the `<h1>` page heading
*/
pageHeading: {
type: String,
default: null
},
/**
* Content layout used when there is a list together with content:
* - `vertical-split` - a 2-column layout with list and default content separated vertically
* - `no-split` - a single column layout; List is shown when `showDetails` is `false`, otherwise the default slot content is shown with a back button to return to the list.
* - 'horizontal-split' - a 2-column layout with list and default content separated horizontally
* On mobile screen `no-split` layout is forced.
*/
layout: {
type: String,
default: "vertical-split",
validator(value) {
return ["no-split", "vertical-split", "horizontal-split"].includes(value);
}
}
},
emits: [
"update:showDetails",
"resize:list"
],
setup() {
return {
isMobile: useIsMobile()
};
},
data() {
return {
contentHeight: 0,
hasList: false,
hasContent: false,
swiping: {},
listPaneSize: this.restorePaneConfig()
};
},
computed: {
paneConfigID() {
if (this.paneConfigKey !== "") {
return "pane-list-size-".concat(this.paneConfigKey);
}
try {
return "pane-list-size-".concat(appName);
} catch (e) {
console.info("[INFO] AppContent:", "falling back to global nextcloud pane config");
return "pane-list-size-nextcloud";
}
},
detailsPaneSize() {
if (this.listPaneSize) {
return 100 - this.listPaneSize;
}
return this.paneDefaults.details.size;
},
paneDefaults() {
return {
list: {
size: this.listSize,
min: this.listMinWidth,
max: this.listMaxWidth
},
// set the inverse values of the details column
// based on the provided (or default) values of the list column
details: {
size: 100 - this.listSize,
min: 100 - this.listMaxWidth,
max: 100 - this.listMinWidth
}
};
}
},
updated() {
this.checkSlots();
},
mounted() {
if (this.allowSwipeNavigation) {
this.swiping = useSwipe(this.$el, {
onSwipeEnd: this.handleSwipe
});
}
this.checkSlots();
this.restorePaneConfig();
},
methods: {
/**
* handle the swipe event
*
* @param {TouchEvent} e The touch event
* @param {import('@vueuse/core').SwipeDirection} direction The swipe direction of the event
*/
handleSwipe(e, direction) {
const minSwipeX = 70;
const touchZone = 300;
if (Math.abs(this.swiping.lengthX) > minSwipeX) {
if (this.swiping.coordsStart.x < touchZone / 2 && direction === "right") {
emit("toggle-navigation", {
open: true
});
} else if (this.swiping.coordsStart.x < touchZone * 1.5 && direction === "left") {
emit("toggle-navigation", {
open: false
});
}
}
},
handlePaneResize(event) {
const listPaneSize = parseInt(event[0].size, 10);
browserStorage.setItem(this.paneConfigID, JSON.stringify(listPaneSize));
this.listPaneSize = listPaneSize;
this.$emit("resize:list", { size: listPaneSize });
console.debug("AppContent pane config", listPaneSize);
},
// $slots is not reactive, we need to update this manually
checkSlots() {
this.hasList = !!this.$scopedSlots.list;
this.hasContent = !!this.$scopedSlots.default;
},
// browserStorage is not reactive, we need to update this manually
restorePaneConfig() {
const listPaneSize = parseInt(browserStorage.getItem(this.paneConfigID), 10);
if (!isNaN(listPaneSize) && listPaneSize !== this.listPaneSize) {
console.debug("AppContent pane config", listPaneSize);
this.listPaneSize = listPaneSize;
return listPaneSize;
}
},
/**
* The user clicked the back arrow from the details view
*/
hideDetails() {
this.$emit("update:showDetails", false);
}
}
};
var _sfc_render = function render2() {
var _vm = this, _c = _vm._self._c;
return _c("main", { staticClass: "app-content no-snapper", class: { "app-content--has-list": _vm.hasList }, attrs: { "id": "app-content-vue" } }, [_vm.pageHeading ? _c("h1", { staticClass: "hidden-visually" }, [_vm._v(" " + _vm._s(_vm.pageHeading) + " ")]) : _vm._e(), _vm.hasList ? [_vm.isMobile || _vm.layout === "no-split" ? _c("div", { staticClass: "app-content-wrapper app-content-wrapper--no-split", class: {
"app-content-wrapper--show-details": _vm.showDetails,
"app-content-wrapper--show-list": !_vm.showDetails,
"app-content-wrapper--mobile": _vm.isMobile
} }, [_vm.showDetails ? _c("NcAppDetailsToggle", { nativeOn: { "click": function($event) {
$event.stopPropagation();
$event.preventDefault();
return _vm.hideDetails.apply(null, arguments);
} } }) : _vm._e(), !_vm.showDetails ? _vm._t("list") : _vm._t("default")], 2) : _vm.layout === "vertical-split" || _vm.layout === "horizontal-split" ? _c("div", { staticClass: "app-content-wrapper" }, [_c("Splitpanes", { staticClass: "default-theme", class: {
"splitpanes--horizontal": _vm.layout === "horizontal-split",
"splitpanes--vertical": _vm.layout === "vertical-split"
}, attrs: { "horizontal": _vm.layout === "horizontal-split" }, on: { "resized": _vm.handlePaneResize } }, [_c("Pane", { staticClass: "splitpanes__pane-list", attrs: { "size": _vm.listPaneSize || _vm.paneDefaults.list.size, "min-size": _vm.paneDefaults.list.min, "max-size": _vm.paneDefaults.list.max } }, [_vm._t("list")], 2), _c("Pane", { staticClass: "splitpanes__pane-details", attrs: { "size": _vm.detailsPaneSize, "min-size": _vm.paneDefaults.details.min, "max-size": _vm.paneDefaults.details.max } }, [_vm._t("default")], 2)], 1)], 1) : _vm._e()] : _vm._e(), !_vm.hasList ? _vm._t("default") : _vm._e()], 2);
};
var _sfc_staticRenderFns = [];
var __component__ = /* @__PURE__ */ normalizeComponent(
_sfc_main,
_sfc_render,
_sfc_staticRenderFns,
false,
null,
"de6986e3"
);
const NcAppContent = __component__.exports;
export {
NcAppContent as N
};