@nextcloud/vue 9.12.0 → 9.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/dist/assets/NcAppContent.css +20 -20
- package/dist/assets/NcAppNavigation.css +13 -13
- package/dist/assets/NcAppNavigationSettings.css +6 -6
- package/dist/assets/NcAppSettingsDialog.css +3 -3
- package/dist/assets/NcAppSettingsShortcutsSection.css +1 -1
- package/dist/assets/NcAppSidebar.css +28 -28
- package/dist/assets/NcAssistantButton.css +9 -9
- package/dist/assets/NcAssistantContent.css +3 -3
- package/dist/assets/NcAssistantIcon.css +4 -4
- package/dist/assets/NcAvatar.css +26 -26
- package/dist/assets/NcBlurHash.css +2 -2
- package/dist/assets/NcDateTimePicker.css +234 -234
- package/dist/assets/NcDialog.css +16 -16
- package/dist/assets/NcFilePicker.css +1 -1
- package/dist/assets/NcFormBox.css +11 -11
- package/dist/assets/NcFormBoxButton.css +2 -2
- package/dist/assets/NcFormBoxItem.css +15 -15
- package/dist/assets/NcFormBoxSwitch.css +2 -2
- package/dist/assets/NcFormGroup.css +7 -7
- package/dist/assets/NcHotkey.css +8 -8
- package/dist/assets/NcHotkeyList.css +2 -2
- package/dist/assets/NcIconToggleSwitch.css +4 -4
- package/dist/assets/NcKbd.css +3 -3
- package/dist/assets/NcModal.css +71 -64
- package/dist/assets/NcPopover.css +16 -16
- package/dist/assets/NcRadioGroup.css +2 -2
- package/dist/assets/NcRadioGroupButton.css +14 -14
- package/dist/assets/NcReferenceWidget.css +24 -23
- package/dist/assets/NcRichContenteditable.css +17 -17
- package/dist/assets/NcSelect.css +8 -13
- package/dist/assets/NcUploadPicker.css +7 -7
- package/dist/assets/autolink.css +3 -3
- package/dist/chunks/NcAppContent.mjs +170 -297
- package/dist/chunks/NcAppContent.mjs.map +1 -1
- package/dist/chunks/NcAppContentList.vue_vue_type_script_setup_true_lang.mjs +21 -0
- package/dist/chunks/NcAppContentList.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
- package/dist/chunks/NcAppNavigation.mjs +7 -4
- package/dist/chunks/NcAppNavigation.mjs.map +1 -1
- package/dist/chunks/NcAppNavigationSettings.mjs +6 -6
- package/dist/chunks/NcAppSettingsDialog.mjs +4 -4
- package/dist/chunks/NcAppSettingsShortcutsSection.mjs +1 -1
- package/dist/chunks/NcAppSidebar.mjs +12 -12
- package/dist/chunks/NcAssistantButton.mjs +7 -7
- package/dist/chunks/NcAssistantContent.mjs +3 -3
- package/dist/chunks/NcAssistantIcon.mjs +4 -4
- package/dist/chunks/NcAvatar.mjs +14 -7
- package/dist/chunks/NcAvatar.mjs.map +1 -1
- package/dist/chunks/NcBlurHash.mjs +2 -2
- package/dist/chunks/NcContent.mjs +1 -1
- package/dist/chunks/NcDateTimePicker.mjs +39 -1
- package/dist/chunks/NcDateTimePicker.mjs.map +1 -1
- package/dist/chunks/NcDialog.mjs +1 -1
- package/dist/chunks/NcDialog.mjs.map +1 -1
- package/dist/chunks/NcFilePicker.mjs +1 -1
- package/dist/chunks/NcFormBox.mjs +5 -5
- package/dist/chunks/NcFormBoxButton.mjs +2 -2
- package/dist/chunks/NcFormBoxItem.mjs +8 -8
- package/dist/chunks/NcFormBoxSwitch.mjs +2 -2
- package/dist/chunks/NcFormGroup.mjs +7 -7
- package/dist/chunks/NcHotkey.mjs +4 -4
- package/dist/chunks/NcHotkeyList.mjs +2 -2
- package/dist/chunks/NcIconToggleSwitch.mjs +2 -2
- package/dist/chunks/NcKbd.mjs +2 -2
- package/dist/chunks/NcMentionBubble.vue_vue_type_style_index_0_scoped_3c4a673d_lang.mjs +7 -7
- package/dist/chunks/NcMentionBubble.vue_vue_type_style_index_0_scoped_3c4a673d_lang.mjs.map +1 -1
- package/dist/chunks/NcModal.mjs +11 -12
- package/dist/chunks/NcModal.mjs.map +1 -1
- package/dist/chunks/NcPopover.mjs +2 -2
- package/dist/chunks/NcPopover.mjs.map +1 -1
- package/dist/chunks/NcRadioGroup.mjs +2 -2
- package/dist/chunks/NcRadioGroupButton.mjs +6 -6
- package/dist/chunks/NcReferenceWidget.mjs +2 -2
- package/dist/chunks/NcReferenceWidget.mjs.map +1 -1
- package/dist/chunks/NcRichContenteditable.mjs +10 -10
- package/dist/chunks/NcSelect.mjs.map +1 -1
- package/dist/chunks/NcUploadPicker.mjs +6 -6
- package/dist/chunks/NcUploadPicker.mjs.map +1 -1
- package/dist/chunks/_l10n.mjs +24 -24
- package/dist/chunks/autolink.mjs +3 -3
- package/dist/components/NcAppContent/NcAppContent.vue.d.ts +77 -149
- package/dist/components/NcAppContent/index.d.ts +5 -0
- package/dist/components/NcAppContentList/NcAppContentList.vue.d.ts +28 -27
- package/dist/components/NcAppContentList/index.d.ts +4 -0
- package/dist/components/NcAppContentList/index.mjs +2 -2
- package/dist/components/NcAvatar/NcAvatar.vue.d.ts +17 -0
- package/dist/components/NcCollectionList/NcCollectionList.vue.d.ts +18 -0
- package/dist/components/NcCollectionList/NcCollectionListItem.vue.d.ts +9 -0
- package/dist/components/NcDashboardWidget/NcDashboardWidget.vue.d.ts +18 -0
- package/dist/components/NcDashboardWidgetItem/NcDashboardWidgetItem.vue.d.ts +9 -0
- package/dist/components/NcDateTimePicker/formatValidation.d.ts +10 -0
- package/dist/components/NcListItemIcon/NcListItemIcon.vue.d.ts +9 -0
- package/dist/components/NcModal/NcModal.vue.d.ts +3 -0
- package/dist/components/NcRichText/NcReferencePicker/NcReferencePickerModal.vue.d.ts +8 -0
- package/dist/components/index.d.ts +2 -2
- package/dist/index.mjs +169 -169
- package/dist/utils/getAvatarUrl.d.ts +4 -0
- package/package.json +11 -11
- package/dist/chunks/NcAppContentList.mjs +0 -33
- package/dist/chunks/NcAppContentList.mjs.map +0 -1
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import '../assets/NcAppContent.css';
|
|
2
|
-
import {
|
|
3
|
-
import { getCapabilities } from "@nextcloud/capabilities";
|
|
2
|
+
import { defineComponent, watch, onMounted, onBeforeUnmount, openBlock, createBlock, unref, normalizeClass, withCtx, createVNode, useModel, ref, computed, createElementBlock, toDisplayString, createCommentVNode, Fragment, withModifiers, withDirectives, createElementVNode, renderSlot, vShow, mergeModels } from "vue";
|
|
4
3
|
import { emit } from "@nextcloud/event-bus";
|
|
5
|
-
import { useSwipe } from "@vueuse/core";
|
|
4
|
+
import { useCurrentElement, useSwipe } from "@vueuse/core";
|
|
6
5
|
import { Splitpanes, Pane } from "splitpanes";
|
|
7
|
-
import { defineComponent, watch, onMounted, onBeforeUnmount, openBlock, createBlock, unref, normalizeClass, withCtx, createVNode, resolveComponent, createElementBlock, toDisplayString, createCommentVNode, Fragment, withModifiers, withDirectives, createElementVNode, renderSlot, vShow } from "vue";
|
|
8
6
|
import { m as mdiArrowRight } from "./mdi.mjs";
|
|
9
7
|
import { useIsMobile } from "../composables/useIsMobile/index.mjs";
|
|
10
|
-
import { r as register,
|
|
8
|
+
import { r as register, J as t29, a as t } from "./_l10n.mjs";
|
|
11
9
|
import { N as NcButton } from "./NcButton.mjs";
|
|
12
10
|
import { N as NcIconSvgWrapper } from "./NcIconSvgWrapper.mjs";
|
|
13
11
|
import { _ as _export_sfc } from "./_plugin-vue_export-helper.mjs";
|
|
14
|
-
import {
|
|
12
|
+
import { a as useAppName, u as useLocalizedAppName } from "./appName.mjs";
|
|
15
13
|
import { l as logger } from "./logger.mjs";
|
|
16
14
|
import { i as isRtl } from "./rtl.mjs";
|
|
17
15
|
import "splitpanes/dist/splitpanes.css";
|
|
16
|
+
import { getBuilder } from "@nextcloud/browser-storage";
|
|
17
|
+
import { getCapabilities } from "@nextcloud/capabilities";
|
|
18
18
|
register(t29);
|
|
19
19
|
const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
20
20
|
__name: "NcAppContentDetailsToggle",
|
|
@@ -57,324 +57,197 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
|
57
57
|
}
|
|
58
58
|
});
|
|
59
59
|
const NcAppContentDetailsToggle = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-a28923a1"]]);
|
|
60
|
+
const _hoisted_1 = {
|
|
61
|
+
key: 0,
|
|
62
|
+
class: "hidden-visually"
|
|
63
|
+
};
|
|
64
|
+
const _hoisted_2 = { class: "app-content-wrapper__list" };
|
|
65
|
+
const _hoisted_3 = {
|
|
66
|
+
key: 1,
|
|
67
|
+
class: "app-content-wrapper"
|
|
68
|
+
};
|
|
60
69
|
const browserStorage = getBuilder("nextcloud").persist().build();
|
|
61
70
|
const instanceName = getCapabilities().theming?.name ?? "Nextcloud";
|
|
62
|
-
const _sfc_main = {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
* Specify the config key for the pane config sizes
|
|
105
|
-
* Default is the global var appName if you use the webpack-vue-config
|
|
106
|
-
*/
|
|
107
|
-
paneConfigKey: {
|
|
108
|
-
type: String,
|
|
109
|
-
default: ""
|
|
110
|
-
},
|
|
111
|
-
/**
|
|
112
|
-
* When in mobile view, only the list or the details are shown.
|
|
113
|
-
*
|
|
114
|
-
* If you provide a list, you need to provide a variable
|
|
115
|
-
* that will be set to true by the user when an element of
|
|
116
|
-
* the list gets selected. The details will then show a back
|
|
117
|
-
* arrow to return to the list that will update this prop to false.
|
|
118
|
-
*/
|
|
119
|
-
showDetails: {
|
|
120
|
-
type: Boolean,
|
|
121
|
-
default: true
|
|
122
|
-
},
|
|
123
|
-
/**
|
|
124
|
-
* Content layout used when there is a list together with content:
|
|
125
|
-
* - `vertical-split` - a 2-column layout with list and default content separated vertically
|
|
126
|
-
* - `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.
|
|
127
|
-
* - 'horizontal-split' - a 2-column layout with list and default content separated horizontally
|
|
128
|
-
* On mobile screen `no-split` layout is forced.
|
|
129
|
-
*/
|
|
130
|
-
layout: {
|
|
131
|
-
type: String,
|
|
132
|
-
default: "vertical-split",
|
|
133
|
-
validator(value) {
|
|
134
|
-
return ["no-split", "vertical-split", "horizontal-split"].includes(value);
|
|
71
|
+
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
72
|
+
__name: "NcAppContent",
|
|
73
|
+
props: /* @__PURE__ */ mergeModels({
|
|
74
|
+
disableSwipe: { type: Boolean, default: false },
|
|
75
|
+
listSize: { default: 20 },
|
|
76
|
+
listMinWidth: { default: 15 },
|
|
77
|
+
listMaxWidth: { default: 40 },
|
|
78
|
+
paneConfigKey: { default: "" },
|
|
79
|
+
layout: { default: "vertical-split" },
|
|
80
|
+
pageHeading: { default: () => void 0 },
|
|
81
|
+
pageTitle: { default: () => void 0 }
|
|
82
|
+
}, {
|
|
83
|
+
"showDetails": { type: Boolean, ...{ default: true } },
|
|
84
|
+
"showDetailsModifiers": {}
|
|
85
|
+
}),
|
|
86
|
+
emits: /* @__PURE__ */ mergeModels(["resizeList", "update:showDetails"], ["update:showDetails"]),
|
|
87
|
+
setup(__props, { emit: __emit }) {
|
|
88
|
+
const showDetails = useModel(__props, "showDetails");
|
|
89
|
+
const emit$1 = __emit;
|
|
90
|
+
const appName = useAppName();
|
|
91
|
+
const localizedAppName = useLocalizedAppName();
|
|
92
|
+
const isMobile = useIsMobile();
|
|
93
|
+
const element = useCurrentElement();
|
|
94
|
+
const swipe = useSwipe(
|
|
95
|
+
// Swiping can be disabled by not providing a target to listen on
|
|
96
|
+
() => __props.disableSwipe ? void 0 : element.value,
|
|
97
|
+
{
|
|
98
|
+
onSwipeEnd(_event, direction) {
|
|
99
|
+
const minSwipeX = 70;
|
|
100
|
+
const touchZone = 300;
|
|
101
|
+
if (Math.abs(swipe.lengthX.value) > minSwipeX) {
|
|
102
|
+
if (swipe.coordsStart.x < touchZone / 2 && direction === "right") {
|
|
103
|
+
emit("toggle-navigation", {
|
|
104
|
+
open: true
|
|
105
|
+
});
|
|
106
|
+
} else if (swipe.coordsStart.x < touchZone * 1.5 && direction === "left") {
|
|
107
|
+
emit("toggle-navigation", {
|
|
108
|
+
open: false
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
135
113
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
type: String,
|
|
142
|
-
default: null
|
|
143
|
-
},
|
|
144
|
-
/**
|
|
145
|
-
* Allow setting the page's `<title>`
|
|
146
|
-
*
|
|
147
|
-
* If a page heading is set it defaults to `{pageHeading} - {appName} - {instanceName}` e.g. `Favorites - Files - MyPersonalCloud`.
|
|
148
|
-
* When the page heading and the app name is the same only one is used, e.g. `Files - Files - MyPersonalCloud` is shown as `Files - MyPersonalCloud`.
|
|
149
|
-
* When setting the prop then the following format will be used: `{pageTitle} - {instanceName}`
|
|
150
|
-
*/
|
|
151
|
-
pageTitle: {
|
|
152
|
-
type: String,
|
|
153
|
-
default: null
|
|
154
|
-
}
|
|
155
|
-
},
|
|
156
|
-
emits: [
|
|
157
|
-
"update:showDetails",
|
|
158
|
-
"resizeList"
|
|
159
|
-
],
|
|
160
|
-
setup() {
|
|
161
|
-
return {
|
|
162
|
-
appName: useAppName(),
|
|
163
|
-
localizedAppName: useLocalizedAppName(),
|
|
164
|
-
isMobile: useIsMobile(),
|
|
165
|
-
isRtl
|
|
166
|
-
};
|
|
167
|
-
},
|
|
168
|
-
data() {
|
|
169
|
-
return {
|
|
170
|
-
contentHeight: 0,
|
|
171
|
-
swiping: {},
|
|
172
|
-
listPaneSize: this.restorePaneConfig()
|
|
173
|
-
};
|
|
174
|
-
},
|
|
175
|
-
computed: {
|
|
176
|
-
paneConfigID() {
|
|
177
|
-
if (this.paneConfigKey !== "") {
|
|
178
|
-
return `pane-list-size-${this.paneConfigKey}`;
|
|
114
|
+
);
|
|
115
|
+
const listPaneSize = ref();
|
|
116
|
+
const paneConfigID = computed(() => {
|
|
117
|
+
if (__props.paneConfigKey !== "") {
|
|
118
|
+
return `pane-list-size-${__props.paneConfigKey}`;
|
|
179
119
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
120
|
+
return `pane-list-size-${appName}`;
|
|
121
|
+
});
|
|
122
|
+
const paneDefaults = computed(() => ({
|
|
123
|
+
list: {
|
|
124
|
+
size: __props.listSize,
|
|
125
|
+
min: __props.listMinWidth,
|
|
126
|
+
max: __props.listMaxWidth
|
|
127
|
+
},
|
|
128
|
+
// set the inverse values of the details column
|
|
129
|
+
// based on the provided (or default) values of the list column
|
|
130
|
+
details: {
|
|
131
|
+
size: 100 - __props.listSize,
|
|
132
|
+
min: 100 - __props.listMaxWidth,
|
|
133
|
+
max: 100 - __props.listMinWidth
|
|
185
134
|
}
|
|
186
|
-
}
|
|
187
|
-
detailsPaneSize() {
|
|
188
|
-
if (
|
|
189
|
-
return 100 -
|
|
135
|
+
}));
|
|
136
|
+
const detailsPaneSize = computed(() => {
|
|
137
|
+
if (listPaneSize.value) {
|
|
138
|
+
return 100 - listPaneSize.value;
|
|
190
139
|
}
|
|
191
|
-
return
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
return {
|
|
195
|
-
list: {
|
|
196
|
-
size: this.listSize,
|
|
197
|
-
min: this.listMinWidth,
|
|
198
|
-
max: this.listMaxWidth
|
|
199
|
-
},
|
|
200
|
-
// set the inverse values of the details column
|
|
201
|
-
// based on the provided (or default) values of the list column
|
|
202
|
-
details: {
|
|
203
|
-
size: 100 - this.listSize,
|
|
204
|
-
min: 100 - this.listMaxWidth,
|
|
205
|
-
max: 100 - this.listMinWidth
|
|
206
|
-
}
|
|
207
|
-
};
|
|
208
|
-
},
|
|
209
|
-
realPageTitle() {
|
|
140
|
+
return paneDefaults.value.details.size;
|
|
141
|
+
});
|
|
142
|
+
const realPageTitle = computed(() => {
|
|
210
143
|
const entries = /* @__PURE__ */ new Set();
|
|
211
|
-
if (
|
|
212
|
-
for (const part of
|
|
144
|
+
if (__props.pageTitle) {
|
|
145
|
+
for (const part of __props.pageTitle.split(" - ")) {
|
|
213
146
|
entries.add(part);
|
|
214
147
|
}
|
|
215
|
-
} else if (
|
|
216
|
-
for (const part of
|
|
148
|
+
} else if (__props.pageHeading) {
|
|
149
|
+
for (const part of __props.pageHeading.split(" - ")) {
|
|
217
150
|
entries.add(part);
|
|
218
151
|
}
|
|
219
152
|
if (entries.size > 0) {
|
|
220
|
-
entries.add(
|
|
153
|
+
entries.add(localizedAppName);
|
|
221
154
|
}
|
|
222
155
|
} else {
|
|
223
156
|
return null;
|
|
224
157
|
}
|
|
225
158
|
entries.add(instanceName);
|
|
226
159
|
return [...entries.values()].join(" - ");
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
immediate: true,
|
|
232
|
-
handler() {
|
|
233
|
-
if (this.realPageTitle !== null) {
|
|
234
|
-
document.title = this.realPageTitle;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
},
|
|
238
|
-
paneConfigKey: {
|
|
239
|
-
immediate: true,
|
|
240
|
-
handler() {
|
|
241
|
-
this.restorePaneConfig();
|
|
160
|
+
});
|
|
161
|
+
watch(realPageTitle, () => {
|
|
162
|
+
if (realPageTitle.value !== null) {
|
|
163
|
+
document.title = realPageTitle.value;
|
|
242
164
|
}
|
|
165
|
+
}, { immediate: true });
|
|
166
|
+
watch(() => __props.paneConfigKey, restorePaneConfig, { immediate: true });
|
|
167
|
+
onMounted(restorePaneConfig);
|
|
168
|
+
function handlePaneResize(event) {
|
|
169
|
+
const size = Math.trunc(event.panes[0].size);
|
|
170
|
+
browserStorage.setItem(paneConfigID.value, JSON.stringify(size));
|
|
171
|
+
listPaneSize.value = size;
|
|
172
|
+
emit$1("resizeList", { size });
|
|
173
|
+
logger.debug("[NcAppContent] pane config", { listPaneSize: size });
|
|
243
174
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
});
|
|
250
|
-
}
|
|
251
|
-
this.restorePaneConfig();
|
|
252
|
-
},
|
|
253
|
-
methods: {
|
|
254
|
-
/**
|
|
255
|
-
* handle the swipe event
|
|
256
|
-
*
|
|
257
|
-
* @param {TouchEvent} e The touch event
|
|
258
|
-
* @param {import('@vueuse/core').SwipeDirection} direction The swipe direction of the event
|
|
259
|
-
*/
|
|
260
|
-
handleSwipe(e, direction) {
|
|
261
|
-
const minSwipeX = 70;
|
|
262
|
-
const touchZone = 300;
|
|
263
|
-
if (Math.abs(this.swiping.lengthX) > minSwipeX) {
|
|
264
|
-
if (this.swiping.coordsStart.x < touchZone / 2 && direction === "right") {
|
|
265
|
-
emit("toggle-navigation", {
|
|
266
|
-
open: true
|
|
267
|
-
});
|
|
268
|
-
} else if (this.swiping.coordsStart.x < touchZone * 1.5 && direction === "left") {
|
|
269
|
-
emit("toggle-navigation", {
|
|
270
|
-
open: false
|
|
271
|
-
});
|
|
272
|
-
}
|
|
175
|
+
function restorePaneConfig() {
|
|
176
|
+
const size = parseInt(browserStorage.getItem(paneConfigID.value) ?? "", 10);
|
|
177
|
+
if (!isNaN(size) && size !== listPaneSize.value) {
|
|
178
|
+
logger.debug("[NcAppContent] pane config", { listPaneSize: size });
|
|
179
|
+
listPaneSize.value = size;
|
|
273
180
|
}
|
|
274
|
-
},
|
|
275
|
-
handlePaneResize(event) {
|
|
276
|
-
const listPaneSize = parseInt(event.panes[0].size, 10);
|
|
277
|
-
browserStorage.setItem(this.paneConfigID, JSON.stringify(listPaneSize));
|
|
278
|
-
this.listPaneSize = listPaneSize;
|
|
279
|
-
this.$emit("resizeList", { size: listPaneSize });
|
|
280
|
-
logger.debug("[NcAppContent] pane config", { listPaneSize });
|
|
281
|
-
},
|
|
282
|
-
// browserStorage is not reactive, we need to update this manually
|
|
283
|
-
restorePaneConfig() {
|
|
284
|
-
const listPaneSize = parseInt(browserStorage.getItem(this.paneConfigID), 10);
|
|
285
|
-
if (!isNaN(listPaneSize) && listPaneSize !== this.listPaneSize) {
|
|
286
|
-
logger.debug("[NcAppContent] pane config", { listPaneSize });
|
|
287
|
-
this.listPaneSize = listPaneSize;
|
|
288
|
-
return listPaneSize;
|
|
289
|
-
}
|
|
290
|
-
},
|
|
291
|
-
/**
|
|
292
|
-
* The user clicked the back arrow from the details view
|
|
293
|
-
*/
|
|
294
|
-
hideDetails() {
|
|
295
|
-
this.$emit("update:showDetails", false);
|
|
296
181
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
class: "hidden-visually"
|
|
302
|
-
};
|
|
303
|
-
const _hoisted_2 = { class: "app-content-wrapper__list" };
|
|
304
|
-
const _hoisted_3 = {
|
|
305
|
-
key: 1,
|
|
306
|
-
class: "app-content-wrapper"
|
|
307
|
-
};
|
|
308
|
-
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
309
|
-
const _component_NcAppContentDetailsToggle = resolveComponent("NcAppContentDetailsToggle");
|
|
310
|
-
const _component_Pane = resolveComponent("Pane");
|
|
311
|
-
const _component_Splitpanes = resolveComponent("Splitpanes");
|
|
312
|
-
return openBlock(), createElementBlock("main", {
|
|
313
|
-
id: "app-content-vue",
|
|
314
|
-
class: normalizeClass(["app-content no-snapper", { "app-content--has-list": !!_ctx.$slots.list }])
|
|
315
|
-
}, [
|
|
316
|
-
$props.pageHeading ? (openBlock(), createElementBlock("h1", _hoisted_1, toDisplayString($props.pageHeading), 1)) : createCommentVNode("", true),
|
|
317
|
-
!!_ctx.$slots.list ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [
|
|
318
|
-
$setup.isMobile || $props.layout === "no-split" ? (openBlock(), createElementBlock("div", {
|
|
319
|
-
key: 0,
|
|
320
|
-
class: normalizeClass(["app-content-wrapper app-content-wrapper--no-split", {
|
|
321
|
-
"app-content-wrapper--show-details": $props.showDetails,
|
|
322
|
-
"app-content-wrapper--show-list": !$props.showDetails,
|
|
323
|
-
"app-content-wrapper--mobile": $setup.isMobile
|
|
324
|
-
}])
|
|
182
|
+
return (_ctx, _cache) => {
|
|
183
|
+
return openBlock(), createElementBlock("main", {
|
|
184
|
+
id: "app-content-vue",
|
|
185
|
+
class: normalizeClass(["app-content no-snapper", { "app-content--has-list": !!_ctx.$slots.list }])
|
|
325
186
|
}, [
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
"
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
createVNode(
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
]),
|
|
356
|
-
_: 3
|
|
357
|
-
}, 8, ["size", "minSize", "maxSize"]),
|
|
358
|
-
createVNode(_component_Pane, {
|
|
359
|
-
class: "splitpanes__pane-details",
|
|
360
|
-
size: $options.detailsPaneSize,
|
|
361
|
-
minSize: $options.paneDefaults.details.min,
|
|
362
|
-
maxSize: $options.paneDefaults.details.max
|
|
187
|
+
__props.pageHeading ? (openBlock(), createElementBlock("h1", _hoisted_1, toDisplayString(__props.pageHeading), 1)) : createCommentVNode("", true),
|
|
188
|
+
!!_ctx.$slots.list ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [
|
|
189
|
+
unref(isMobile) || __props.layout === "no-split" ? (openBlock(), createElementBlock("div", {
|
|
190
|
+
key: 0,
|
|
191
|
+
class: normalizeClass(["app-content-wrapper app-content-wrapper--no-split", {
|
|
192
|
+
"app-content-wrapper--show-details": showDetails.value,
|
|
193
|
+
"app-content-wrapper--show-list": !showDetails.value,
|
|
194
|
+
"app-content-wrapper--mobile": unref(isMobile)
|
|
195
|
+
}])
|
|
196
|
+
}, [
|
|
197
|
+
showDetails.value ? (openBlock(), createBlock(NcAppContentDetailsToggle, {
|
|
198
|
+
key: 0,
|
|
199
|
+
onClick: _cache[0] || (_cache[0] = withModifiers(($event) => showDetails.value = false, ["stop", "prevent"]))
|
|
200
|
+
})) : createCommentVNode("", true),
|
|
201
|
+
withDirectives(createElementVNode("div", _hoisted_2, [
|
|
202
|
+
renderSlot(_ctx.$slots, "list", {}, void 0, true)
|
|
203
|
+
], 512), [
|
|
204
|
+
[vShow, !showDetails.value]
|
|
205
|
+
]),
|
|
206
|
+
showDetails.value ? renderSlot(_ctx.$slots, "default", {}, void 0, true, 1) : createCommentVNode("", true)
|
|
207
|
+
], 2)) : __props.layout === "vertical-split" || __props.layout === "horizontal-split" ? (openBlock(), createElementBlock("div", _hoisted_3, [
|
|
208
|
+
createVNode(unref(Splitpanes), {
|
|
209
|
+
horizontal: __props.layout === "horizontal-split",
|
|
210
|
+
class: normalizeClass(["default-theme", {
|
|
211
|
+
"splitpanes--horizontal": __props.layout === "horizontal-split",
|
|
212
|
+
"splitpanes--vertical": __props.layout === "vertical-split"
|
|
213
|
+
}]),
|
|
214
|
+
rtl: unref(isRtl),
|
|
215
|
+
onResized: handlePaneResize
|
|
363
216
|
}, {
|
|
364
217
|
default: withCtx(() => [
|
|
365
|
-
|
|
218
|
+
createVNode(unref(Pane), {
|
|
219
|
+
class: "splitpanes__pane-list",
|
|
220
|
+
size: listPaneSize.value || paneDefaults.value.list.size,
|
|
221
|
+
minSize: paneDefaults.value.list.min,
|
|
222
|
+
maxSize: paneDefaults.value.list.max
|
|
223
|
+
}, {
|
|
224
|
+
default: withCtx(() => [
|
|
225
|
+
renderSlot(_ctx.$slots, "list", {}, void 0, true)
|
|
226
|
+
]),
|
|
227
|
+
_: 3
|
|
228
|
+
}, 8, ["size", "minSize", "maxSize"]),
|
|
229
|
+
createVNode(unref(Pane), {
|
|
230
|
+
class: "splitpanes__pane-details",
|
|
231
|
+
size: detailsPaneSize.value,
|
|
232
|
+
minSize: paneDefaults.value.details.min,
|
|
233
|
+
maxSize: paneDefaults.value.details.max
|
|
234
|
+
}, {
|
|
235
|
+
default: withCtx(() => [
|
|
236
|
+
renderSlot(_ctx.$slots, "default", {}, void 0, true)
|
|
237
|
+
]),
|
|
238
|
+
_: 3
|
|
239
|
+
}, 8, ["size", "minSize", "maxSize"])
|
|
366
240
|
]),
|
|
367
241
|
_: 3
|
|
368
|
-
}, 8, ["
|
|
369
|
-
]),
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
]
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
const NcAppContent = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-51427d61"]]);
|
|
242
|
+
}, 8, ["horizontal", "class", "rtl"])
|
|
243
|
+
])) : createCommentVNode("", true)
|
|
244
|
+
], 64)) : createCommentVNode("", true),
|
|
245
|
+
!_ctx.$slots.list ? renderSlot(_ctx.$slots, "default", {}, void 0, true, 2) : createCommentVNode("", true)
|
|
246
|
+
], 2);
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
const NcAppContent = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-5de09463"]]);
|
|
378
251
|
export {
|
|
379
252
|
NcAppContent as N
|
|
380
253
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NcAppContent.mjs","sources":["../../src/components/NcAppContent/NcAppContentDetailsToggle.vue","../../src/components/NcAppContent/NcAppContent.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<script setup lang=\"ts\">\nimport { mdiArrowRight } from '@mdi/js'\nimport { emit } from '@nextcloud/event-bus'\nimport { onBeforeUnmount, onMounted, watch } from 'vue'\nimport { useIsMobile } from '../../composables/useIsMobile/index.js'\nimport { t } from '../../l10n.ts'\nimport NcButton from '../NcButton/index.ts'\nimport NcIconSvgWrapper from '../NcIconSvgWrapper/index.ts'\n\nconst isMobile = useIsMobile()\nwatch(isMobile, toggleAppNavigationButton)\n\nonMounted(() => {\n\ttoggleAppNavigationButton(isMobile.value)\n})\n\nonBeforeUnmount(() => {\n\tif (isMobile.value) {\n\t\ttoggleAppNavigationButton(false)\n\t}\n})\n\n/**\n * Toggle the app navigation button and hide it if needed.\n *\n * @param hide - if true the navigation toggle is visually hidden\n */\nfunction toggleAppNavigationButton(hide: boolean = true) {\n\tconst appNavigationToggle = document.querySelector<HTMLElement>('.app-navigation .app-navigation-toggle')\n\tif (appNavigationToggle) {\n\t\tappNavigationToggle.style.display = hide ? 'none' : ''\n\n\t\t// If we hide the NavigationToggle, we need to make sure the Navigation is also closed\n\t\tif (hide === true) {\n\t\t\temit('toggle-navigation', { open: false })\n\t\t}\n\t}\n}\n</script>\n\n<template>\n\t<NcButton\n\t\t:aria-label=\"t('Go back to the list')\"\n\t\tclass=\"app-details-toggle\"\n\t\t:class=\"{ 'app-details-toggle--mobile': isMobile }\"\n\t\t:title=\"t('Go back to the list')\"\n\t\tvariant=\"tertiary\">\n\t\t<template #icon>\n\t\t\t<NcIconSvgWrapper directional :path=\"mdiArrowRight\" />\n\t\t</template>\n\t</NcButton>\n</template>\n\n<style lang=\"scss\" scoped>\n.app-details-toggle {\n\tposition: sticky;\n\twidth: var(--default-clickable-area);\n\theight: var(--default-clickable-area);\n\tpadding: $icon-margin;\n\tcursor: pointer;\n\topacity: .6;\n\ttransform: rotate(180deg);\n\tbackground-color: var(--color-main-background);\n\tz-index: 2000;\n\n\ttop: var(--app-navigation-padding);\n\t// Navigation Toggle button width + 2 paddings around\n\tinset-inline-start: calc(var(--default-clickable-area) + var(--app-navigation-padding) * 2);\n\t&--mobile {\n\t\t// There is no NavigationToggle button\n\t\tinset-inline-start: var(--app-navigation-padding);\n\t}\n\n\t&:active,\n\t&:hover,\n\t&:focus {\n\t\topacity: 1;\n\t}\n}\n\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<docs>\n### General description\n\nThis components provides a wrapper around the main app's content.\n\nSingle-column layouts can just use the default slot. A resizable column\ncan be added by providing content to the named slot `list`.\n\n### CSS variables\nIn the css section some css variables are declared and will be available for\nall the children of the NcAppContent component\n\n### Examples\n\n#### Usage: Single-column content\n```vue\n<template>\n\t<NcAppContent>\n\t\t<h2>Single-column main content</h2>\n\t</NcAppContent>\n</template>\n```\n\n#### Usage: Two resizable columns\n```vue\n<template>\n\t<NcAppContent>\n\t\t<template #list>\n\t\t\t<div>Resizable list content</div>\n\t\t</template>\n\n\t\t<div>Main content</div>\n\t</NcAppContent>\n</template>\n```\n\n#### Overriding Defaults\nThe default, min and max sizes (in percent) of the resizable list column can be overridden.\nThe list size must be between the min and the max width value.\n\n```\n<NcAppContent\n\t:list-size=\"35\"\n\t:list-min-width=\"20\"\n\t:list-max-width=\"45\"\n>...</NcAppContent>\n```\n\n#### Usage: Custom document title\nFor accessibility reasons every document should have a `h1` heading,\nthis is visually hidden, but required for a semantically correct document.\nYou can use your app name or current view for the heading.\n\nAdditionally you can set a custom document title, e.g. to show the current status.\n\n```vue\n<template>\n\t<NcAppContent :pageHeading=\"heading ? 'Heading' : undefined\" :pageTitle=\"title ? 'Title' : undefined\" >\n\t\t<NcCheckboxRadioSwitch type=\"switch\" :checked.sync=\"title\">\n\t\t\tToggle title\n\t\t</NcCheckboxRadioSwitch>\n\t\t<NcCheckboxRadioSwitch type=\"switch\" :checked.sync=\"heading\">\n\t\t\tToggle Heading\n\t\t</NcCheckboxRadioSwitch>\n\t\t<NcButton @click=\"reset\">Reset</NcButton>\n\t</NcAppContent>\n</template>\n\n<script>\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\theading: false,\n\t\t\ttitle: false,\n\t\t}\n\t},\n\tmethods: {\n\t\treset() {\n\t\t\tthis.heading = false\n\t\t\tthis.title = false\n\t\t\tdocument.title = ''\n\t\t},\n\t},\n}\n</script>\n```\n</docs>\n\n<template>\n\t<main id=\"app-content-vue\" class=\"app-content no-snapper\" :class=\"{ 'app-content--has-list': !!$slots.list }\">\n\t\t<h1 v-if=\"pageHeading\" class=\"hidden-visually\">\n\t\t\t{{ pageHeading }}\n\t\t</h1>\n\n\t\t<template v-if=\"!!$slots.list\">\n\t\t\t<!-- Mobile view does not allow resizeable panes -->\n\t\t\t<div\n\t\t\t\tv-if=\"isMobile || layout === 'no-split'\"\n\t\t\t\tclass=\"app-content-wrapper app-content-wrapper--no-split\"\n\t\t\t\t:class=\"{\n\t\t\t\t\t'app-content-wrapper--show-details': showDetails,\n\t\t\t\t\t'app-content-wrapper--show-list': !showDetails,\n\t\t\t\t\t'app-content-wrapper--mobile': isMobile,\n\t\t\t\t}\">\n\t\t\t\t<NcAppContentDetailsToggle v-if=\"showDetails\" @click.stop.prevent=\"hideDetails\" />\n\n\t\t\t\t<div v-show=\"!showDetails\" class=\"app-content-wrapper__list\">\n\t\t\t\t\t<slot name=\"list\" />\n\t\t\t\t</div>\n\t\t\t\t<slot v-if=\"showDetails\" />\n\t\t\t</div>\n\t\t\t<div v-else-if=\"layout === 'vertical-split' || layout === 'horizontal-split'\" class=\"app-content-wrapper\">\n\t\t\t\t<Splitpanes\n\t\t\t\t\t:horizontal=\"layout === 'horizontal-split'\"\n\t\t\t\t\tclass=\"default-theme\"\n\t\t\t\t\t:class=\"{\n\t\t\t\t\t\t'splitpanes--horizontal': layout === 'horizontal-split',\n\t\t\t\t\t\t'splitpanes--vertical': layout === 'vertical-split',\n\t\t\t\t\t}\"\n\t\t\t\t\t:rtl=\"isRtl\"\n\t\t\t\t\t@resized=\"handlePaneResize\">\n\t\t\t\t\t<Pane\n\t\t\t\t\t\tclass=\"splitpanes__pane-list\"\n\t\t\t\t\t\t:size=\"listPaneSize || paneDefaults.list.size\"\n\t\t\t\t\t\t:minSize=\"paneDefaults.list.min\"\n\t\t\t\t\t\t:maxSize=\"paneDefaults.list.max\">\n\t\t\t\t\t\t<!-- @slot Provide a list to the app content -->\n\t\t\t\t\t\t<slot name=\"list\" />\n\t\t\t\t\t</Pane>\n\n\t\t\t\t\t<Pane\n\t\t\t\t\t\tclass=\"splitpanes__pane-details\"\n\t\t\t\t\t\t:size=\"detailsPaneSize\"\n\t\t\t\t\t\t:minSize=\"paneDefaults.details.min\"\n\t\t\t\t\t\t:maxSize=\"paneDefaults.details.max\">\n\t\t\t\t\t\t<!-- @slot Provide the main content to the app content -->\n\t\t\t\t\t\t<slot />\n\t\t\t\t\t</Pane>\n\t\t\t\t</Splitpanes>\n\t\t\t</div>\n\t\t</template>\n\t\t<!-- @slot Provide the main content to the app content -->\n\t\t<slot v-if=\"!$slots.list\" />\n\t</main>\n</template>\n\n<script>\nimport { getBuilder } from '@nextcloud/browser-storage'\nimport { getCapabilities } from '@nextcloud/capabilities'\nimport { emit } from '@nextcloud/event-bus'\nimport { useSwipe } from '@vueuse/core'\nimport { Pane, Splitpanes } from 'splitpanes'\nimport NcAppContentDetailsToggle from './NcAppContentDetailsToggle.vue'\nimport { useIsMobile } from '../../composables/useIsMobile/index.js'\nimport { useAppName, useLocalizedAppName } from '../../utils/appName.ts'\nimport { logger } from '../../utils/logger.ts'\nimport { isRtl } from '../../utils/rtl.ts'\n\nimport 'splitpanes/dist/splitpanes.css'\n\nconst browserStorage = getBuilder('nextcloud').persist().build()\nconst instanceName = getCapabilities().theming?.name ?? 'Nextcloud'\n\n/**\n * App content container to be used for the main content of your app\n *\n */\nexport default {\n\tname: 'NcAppContent',\n\n\tcomponents: {\n\t\tNcAppContentDetailsToggle,\n\t\tPane,\n\t\tSplitpanes,\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * Allows to disable the control by swipe of the app navigation open state.\n\t\t */\n\t\tdisableSwipe: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Allows you to set the default width of the resizable list in % on vertical-split\n\t\t * or respectively the default height on horizontal-split.\n\t\t *\n\t\t * Must be between `listMinWidth` and `listMaxWidth`.\n\t\t */\n\t\tlistSize: {\n\t\t\ttype: Number,\n\t\t\tdefault: 20,\n\t\t},\n\n\t\t/**\n\t\t * Allows you to set the minimum width of the list column in % on vertical-split\n\t\t * or respectively the minimum height on horizontal-split.\n\t\t */\n\t\tlistMinWidth: {\n\t\t\ttype: Number,\n\t\t\tdefault: 15,\n\t\t},\n\n\t\t/**\n\t\t * Allows you to set the maximum width of the list column in % on vertical-split\n\t\t * or respectively the maximum height on horizontal-split.\n\t\t */\n\t\tlistMaxWidth: {\n\t\t\ttype: Number,\n\t\t\tdefault: 40,\n\t\t},\n\n\t\t/**\n\t\t * Specify the config key for the pane config sizes\n\t\t * Default is the global var appName if you use the webpack-vue-config\n\t\t */\n\t\tpaneConfigKey: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * When in mobile view, only the list or the details are shown.\n\t\t *\n\t\t * If you provide a list, you need to provide a variable\n\t\t * that will be set to true by the user when an element of\n\t\t * the list gets selected. The details will then show a back\n\t\t * arrow to return to the list that will update this prop to false.\n\t\t */\n\t\tshowDetails: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Content layout used when there is a list together with content:\n\t\t * - `vertical-split` - a 2-column layout with list and default content separated vertically\n\t\t * - `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.\n\t\t * - 'horizontal-split' - a 2-column layout with list and default content separated horizontally\n\t\t * On mobile screen `no-split` layout is forced.\n\t\t */\n\t\tlayout: {\n\t\t\ttype: String,\n\t\t\tdefault: 'vertical-split',\n\t\t\tvalidator(value) {\n\t\t\t\treturn ['no-split', 'vertical-split', 'horizontal-split'].includes(value)\n\t\t\t},\n\t\t},\n\n\t\t/**\n\t\t * Specify the `<h1>` page heading\n\t\t */\n\t\tpageHeading: {\n\t\t\ttype: String,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Allow setting the page's `<title>`\n\t\t *\n\t\t * If a page heading is set it defaults to `{pageHeading} - {appName} - {instanceName}` e.g. `Favorites - Files - MyPersonalCloud`.\n\t\t * When the page heading and the app name is the same only one is used, e.g. `Files - Files - MyPersonalCloud` is shown as `Files - MyPersonalCloud`.\n\t\t * When setting the prop then the following format will be used: `{pageTitle} - {instanceName}`\n\t\t */\n\t\tpageTitle: {\n\t\t\ttype: String,\n\t\t\tdefault: null,\n\t\t},\n\t},\n\n\temits: [\n\t\t'update:showDetails',\n\t\t'resizeList',\n\t],\n\n\tsetup() {\n\t\treturn {\n\t\t\tappName: useAppName(),\n\t\t\tlocalizedAppName: useLocalizedAppName(),\n\t\t\tisMobile: useIsMobile(),\n\t\t\tisRtl,\n\t\t}\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tcontentHeight: 0,\n\t\t\tswiping: {},\n\t\t\tlistPaneSize: this.restorePaneConfig(),\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tpaneConfigID() {\n\t\t\t// If provided, let's use it\n\t\t\tif (this.paneConfigKey !== '') {\n\t\t\t\treturn `pane-list-size-${this.paneConfigKey}`\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\t// Using the webpack-vue-config, appName is a global variable\n\t\t\t\t// This will throw a ReferenceError when the global variable is missing\n\t\t\t\t// In that case either you provide paneConfigKey or else it fallback\n\t\t\t\t// to a global storage key\n\t\t\t\treturn `pane-list-size-${this.appName}`\n\t\t\t} catch {\n\t\t\t\tlogger.info('[NcAppContent]: falling back to global nextcloud pane config')\n\t\t\t\treturn 'pane-list-size-nextcloud'\n\t\t\t}\n\t\t},\n\n\t\tdetailsPaneSize() {\n\t\t\tif (this.listPaneSize) {\n\t\t\t\treturn 100 - this.listPaneSize\n\t\t\t}\n\t\t\treturn this.paneDefaults.details.size\n\t\t},\n\n\t\tpaneDefaults() {\n\t\t\treturn {\n\t\t\t\tlist: {\n\t\t\t\t\tsize: this.listSize,\n\t\t\t\t\tmin: this.listMinWidth,\n\t\t\t\t\tmax: this.listMaxWidth,\n\t\t\t\t},\n\n\t\t\t\t// set the inverse values of the details column\n\t\t\t\t// based on the provided (or default) values of the list column\n\t\t\t\tdetails: {\n\t\t\t\t\tsize: 100 - this.listSize,\n\t\t\t\t\tmin: 100 - this.listMaxWidth,\n\t\t\t\t\tmax: 100 - this.listMinWidth,\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\n\t\trealPageTitle() {\n\t\t\tconst entries = new Set()\n\t\t\tif (this.pageTitle) {\n\t\t\t\t// when page title is set we only use that\n\t\t\t\t// we still split to remove duplicated instanceName\n\t\t\t\tfor (const part of this.pageTitle.split(' - ')) {\n\t\t\t\t\tentries.add(part)\n\t\t\t\t}\n\t\t\t} else if (this.pageHeading) {\n\t\t\t\t// when the page heading is provided but not the title\n\t\t\t\t// then we split to remove duplicates\n\t\t\t\t// but also add the localized app name\n\t\t\t\tfor (const part of this.pageHeading.split(' - ')) {\n\t\t\t\t\tentries.add(part)\n\t\t\t\t}\n\n\t\t\t\tif (entries.size > 0) {\n\t\t\t\t\tentries.add(this.localizedAppName)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn null\n\t\t\t}\n\n\t\t\tentries.add(instanceName)\n\t\t\treturn [...entries.values()].join(' - ')\n\t\t},\n\t},\n\n\twatch: {\n\t\trealPageTitle: {\n\t\t\timmediate: true,\n\t\t\thandler() {\n\t\t\t\tif (this.realPageTitle !== null) {\n\t\t\t\t\tdocument.title = this.realPageTitle\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\n\t\tpaneConfigKey: {\n\t\t\timmediate: true,\n\t\t\thandler() {\n\t\t\t\tthis.restorePaneConfig()\n\t\t\t},\n\t\t},\n\t},\n\n\tmounted() {\n\t\tif (!this.disableSwipe) {\n\t\t\tthis.swiping = useSwipe(this.$el, {\n\t\t\t\tonSwipeEnd: this.handleSwipe,\n\t\t\t})\n\t\t}\n\n\t\tthis.restorePaneConfig()\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * handle the swipe event\n\t\t *\n\t\t * @param {TouchEvent} e The touch event\n\t\t * @param {import('@vueuse/core').SwipeDirection} direction The swipe direction of the event\n\t\t */\n\t\thandleSwipe(e, direction) {\n\t\t\tconst minSwipeX = 70\n\t\t\tconst touchZone = 300\n\t\t\tif (Math.abs(this.swiping.lengthX) > minSwipeX) {\n\t\t\t\tif (this.swiping.coordsStart.x < (touchZone / 2) && direction === 'right') {\n\t\t\t\t\temit('toggle-navigation', {\n\t\t\t\t\t\topen: true,\n\t\t\t\t\t})\n\t\t\t\t} else if (this.swiping.coordsStart.x < touchZone * 1.5 && direction === 'left') {\n\t\t\t\t\temit('toggle-navigation', {\n\t\t\t\t\t\topen: false,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\thandlePaneResize(event) {\n\t\t\tconst listPaneSize = parseInt(event.panes[0].size, 10)\n\t\t\tbrowserStorage.setItem(this.paneConfigID, JSON.stringify(listPaneSize))\n\t\t\tthis.listPaneSize = listPaneSize\n\t\t\t/**\n\t\t\t * Emitted when the list pane is resized by the user\n\t\t\t */\n\t\t\tthis.$emit('resizeList', { size: listPaneSize })\n\t\t\tlogger.debug('[NcAppContent] pane config', { listPaneSize })\n\t\t},\n\n\t\t// browserStorage is not reactive, we need to update this manually\n\t\trestorePaneConfig() {\n\t\t\tconst listPaneSize = parseInt(browserStorage.getItem(this.paneConfigID), 10)\n\t\t\tif (!isNaN(listPaneSize) && listPaneSize !== this.listPaneSize) {\n\t\t\t\tlogger.debug('[NcAppContent] pane config', { listPaneSize })\n\t\t\t\tthis.listPaneSize = listPaneSize\n\t\t\t\treturn listPaneSize\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The user clicked the back arrow from the details view\n\t\t */\n\t\thideDetails() {\n\t\t\tthis.$emit('update:showDetails', false)\n\t\t},\n\t},\n}\n</script>\n\n<style lang=\"scss\" scoped>\n\n.app-content {\n\tposition: initial;\n\tz-index: 1000;\n\tflex-basis: 100vw;\n\theight: 100%;\n\t// Overriding server styles TODO: cleanup!\n\tmargin: 0 !important;\n\tbackground-color: var(--color-main-background);\n\tmin-width: 0;\n\n\t&:not(.app-content--has-list) {\n\t\toverflow: auto;\n\t}\n}\n\n.app-content-wrapper {\n\tposition: relative;\n\twidth: 100%;\n\theight: 100%;\n}\n\n// Mobile list/details handling\n.app-content-wrapper--no-split {\n\t&.app-content-wrapper--show-list :deep() {\n\t\t.app-content-list {\n\t\t\tdisplay: flex;\n\t\t}\n\t\t.app-content-details {\n\t\t\tdisplay: none;\n\t\t}\n\t}\n\t&.app-content-wrapper--show-details :deep() {\n\t\t.app-content-list {\n\t\t\tdisplay: none;\n\t\t}\n\t\t.app-content-details {\n\t\t\tdisplay: block;\n\t\t}\n\t}\n}\n\n:deep(.splitpanes.default-theme) {\n\t.app-content-list {\n\t\tmax-width: none;\n\t\t/* Thin scrollbar is hard to catch on resizable columns */\n\t\tscrollbar-width: auto;\n\t}\n\n\t.splitpanes__pane {\n\t\tbackground-color: transparent;\n\t\ttransition: none;\n\n\t\t&-list {\n\t\t\tmin-width: 300px;\n\t\t\tposition: sticky;\n\n\t\t\t@media only screen and (width < $breakpoint-mobile) {\n\t\t\t\tdisplay: none;\n\t\t\t}\n\t\t}\n\n\t\t&-details {\n\t\t\toverflow-y: auto;\n\n\t\t\t@media only screen and (width < $breakpoint-mobile) {\n\t\t\t\tmin-width: 100%;\n\t\t\t}\n\t\t}\n\t}\n\n\t.splitpanes__splitter {\n\t\tbackground-color: var(--color-main-background);\n\t\t&::before, &::after {\n\t\t\tbackground-color: var(--color-border);\n\t\t}\n\t}\n\n\t&.splitpanes--vertical .splitpanes__splitter {\n\t\tborder-inline-start: 1px solid var(--color-border);\n\t}\n\n\t&.splitpanes--horizontal .splitpanes__splitter {\n\t\tborder-top: 1px solid var(--color-border);\n\t}\n}\n\n.app-content-wrapper--show-list {\n\t:deep(.app-content-list) {\n\t\tmax-width: none;\n\t}\n}\n\n.app-content-wrapper__list {\n\theight: 100%;\n}\n</style>\n"],"names":["_createBlock","_unref","_normalizeClass","_createVNode","_createElementBlock","_toDisplayString","_Fragment","_withDirectives","_createElementVNode","_renderSlot","_openBlock"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"NcAppContent.mjs","sources":["../../src/components/NcAppContent/NcAppContentDetailsToggle.vue","../../src/components/NcAppContent/NcAppContent.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<script setup lang=\"ts\">\nimport { mdiArrowRight } from '@mdi/js'\nimport { emit } from '@nextcloud/event-bus'\nimport { onBeforeUnmount, onMounted, watch } from 'vue'\nimport { useIsMobile } from '../../composables/useIsMobile/index.js'\nimport { t } from '../../l10n.ts'\nimport NcButton from '../NcButton/index.ts'\nimport NcIconSvgWrapper from '../NcIconSvgWrapper/index.ts'\n\nconst isMobile = useIsMobile()\nwatch(isMobile, toggleAppNavigationButton)\n\nonMounted(() => {\n\ttoggleAppNavigationButton(isMobile.value)\n})\n\nonBeforeUnmount(() => {\n\tif (isMobile.value) {\n\t\ttoggleAppNavigationButton(false)\n\t}\n})\n\n/**\n * Toggle the app navigation button and hide it if needed.\n *\n * @param hide - if true the navigation toggle is visually hidden\n */\nfunction toggleAppNavigationButton(hide: boolean = true) {\n\tconst appNavigationToggle = document.querySelector<HTMLElement>('.app-navigation .app-navigation-toggle')\n\tif (appNavigationToggle) {\n\t\tappNavigationToggle.style.display = hide ? 'none' : ''\n\n\t\t// If we hide the NavigationToggle, we need to make sure the Navigation is also closed\n\t\tif (hide === true) {\n\t\t\temit('toggle-navigation', { open: false })\n\t\t}\n\t}\n}\n</script>\n\n<template>\n\t<NcButton\n\t\t:aria-label=\"t('Go back to the list')\"\n\t\tclass=\"app-details-toggle\"\n\t\t:class=\"{ 'app-details-toggle--mobile': isMobile }\"\n\t\t:title=\"t('Go back to the list')\"\n\t\tvariant=\"tertiary\">\n\t\t<template #icon>\n\t\t\t<NcIconSvgWrapper directional :path=\"mdiArrowRight\" />\n\t\t</template>\n\t</NcButton>\n</template>\n\n<style lang=\"scss\" scoped>\n.app-details-toggle {\n\tposition: sticky;\n\twidth: var(--default-clickable-area);\n\theight: var(--default-clickable-area);\n\tpadding: $icon-margin;\n\tcursor: pointer;\n\topacity: .6;\n\ttransform: rotate(180deg);\n\tbackground-color: var(--color-main-background);\n\tz-index: 2000;\n\n\ttop: var(--app-navigation-padding);\n\t// Navigation Toggle button width + 2 paddings around\n\tinset-inline-start: calc(var(--default-clickable-area) + var(--app-navigation-padding) * 2);\n\t&--mobile {\n\t\t// There is no NavigationToggle button\n\t\tinset-inline-start: var(--app-navigation-padding);\n\t}\n\n\t&:active,\n\t&:hover,\n\t&:focus {\n\t\topacity: 1;\n\t}\n}\n\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<script lang=\"ts\">\nimport { getBuilder } from '@nextcloud/browser-storage'\nimport { getCapabilities } from '@nextcloud/capabilities'\n\n/**\n * Content layout used when a list is provided together with the main content.\n */\nexport type AppContentLayout = 'no-split' | 'vertical-split' | 'horizontal-split'\n\n/**\n * Payload of the `resized` event of the splitpanes component.\n */\ninterface SplitpanesResizedEvent {\n\tpanes: { min: number, max: number, size: number }[]\n}\n\nconst browserStorage = getBuilder('nextcloud').persist().build()\nconst instanceName = (getCapabilities() as { theming?: { name?: string } }).theming?.name ?? 'Nextcloud'\n</script>\n\n<script setup lang=\"ts\">\nimport type { Slot } from 'vue'\n\nimport { emit as emitBusEvent } from '@nextcloud/event-bus'\nimport { useCurrentElement, useSwipe } from '@vueuse/core'\nimport { Pane, Splitpanes } from 'splitpanes'\nimport { computed, onMounted, ref, watch } from 'vue'\nimport NcAppContentDetailsToggle from './NcAppContentDetailsToggle.vue'\nimport { useIsMobile } from '../../composables/useIsMobile/index.ts'\nimport { useAppName, useLocalizedAppName } from '../../utils/appName.ts'\nimport { logger } from '../../utils/logger.ts'\nimport { isRtl } from '../../utils/rtl.ts'\n\nimport 'splitpanes/dist/splitpanes.css'\n\n/**\n * When in mobile view, only the list or the details are shown.\n *\n * If you provide a list, you need to provide a variable\n * that will be set to true by the user when an element of\n * the list gets selected. The details will then show a back\n * arrow to return to the list that will update this model to false.\n */\nconst showDetails = defineModel<boolean>('showDetails', { default: true })\n\nconst {\n\tdisableSwipe = false,\n\tlayout = 'vertical-split',\n\tlistMaxWidth = 40,\n\tlistMinWidth = 15,\n\tlistSize = 20,\n\tpageHeading = undefined,\n\tpageTitle = undefined,\n\tpaneConfigKey = '',\n} = defineProps<{\n\t/**\n\t * Allows to disable the control by swipe of the app navigation open state.\n\t */\n\tdisableSwipe?: boolean\n\n\t/**\n\t * Allows you to set the default width of the resizable list in % on vertical-split\n\t * or respectively the default height on horizontal-split.\n\t *\n\t * Must be between `listMinWidth` and `listMaxWidth`.\n\t *\n\t * @default 20\n\t */\n\tlistSize?: number\n\n\t/**\n\t * Allows you to set the minimum width of the list column in % on vertical-split\n\t * or respectively the minimum height on horizontal-split.\n\t *\n\t * @default 15\n\t */\n\tlistMinWidth?: number\n\n\t/**\n\t * Allows you to set the maximum width of the list column in % on vertical-split\n\t * or respectively the maximum height on horizontal-split.\n\t *\n\t * @default 40\n\t */\n\tlistMaxWidth?: number\n\n\t/**\n\t * Specify the config key for the pane config sizes\n\t * Default is the global var appName if you use the webpack-vue-config\n\t */\n\tpaneConfigKey?: string\n\n\t/**\n\t * Content layout used when there is a list together with content:\n\t * - `vertical-split` - a 2-column layout with list and default content separated vertically\n\t * - `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.\n\t * - 'horizontal-split' - a 2-column layout with list and default content separated horizontally\n\t * On mobile screen `no-split` layout is forced.\n\t *\n\t * @default 'vertical-split'\n\t */\n\tlayout?: AppContentLayout\n\n\t/**\n\t * Specify the `<h1>` page heading\n\t */\n\tpageHeading?: string | null\n\n\t/**\n\t * Allow setting the page's `<title>`\n\t *\n\t * If a page heading is set it defaults to `{pageHeading} - {appName} - {instanceName}` e.g. `Favorites - Files - MyPersonalCloud`.\n\t * When the page heading and the app name is the same only one is used, e.g. `Files - Files - MyPersonalCloud` is shown as `Files - MyPersonalCloud`.\n\t * When setting the prop then the following format will be used: `{pageTitle} - {instanceName}`\n\t */\n\tpageTitle?: string | null\n}>()\n\nconst emit = defineEmits<{\n\t/**\n\t * Emitted when the list pane is resized by the user\n\t */\n\tresizeList: [payload: { size: number }]\n\n\t/**\n\t * Emitted when the user clicked the back arrow from the details view\n\t *\n\t * @param showDetails - The new details state\n\t */\n\t'update:showDetails': [showDetails: boolean]\n}>()\n\ndefineSlots<{\n\t/**\n\t * Provide the main content to the app content\n\t */\n\tdefault?: Slot\n\n\t/**\n\t * Provide a list to the app content\n\t */\n\tlist?: Slot\n}>()\n\nconst appName = useAppName()\nconst localizedAppName = useLocalizedAppName()\nconst isMobile = useIsMobile()\n\nconst element = useCurrentElement<HTMLElement>()\nconst swipe = useSwipe(\n\t// Swiping can be disabled by not providing a target to listen on\n\t() => disableSwipe ? undefined : element.value,\n\t{\n\t\tonSwipeEnd(_event, direction) {\n\t\t\tconst minSwipeX = 70\n\t\t\tconst touchZone = 300\n\t\t\tif (Math.abs(swipe.lengthX.value) > minSwipeX) {\n\t\t\t\tif (swipe.coordsStart.x < (touchZone / 2) && direction === 'right') {\n\t\t\t\t\temitBusEvent('toggle-navigation', {\n\t\t\t\t\t\topen: true,\n\t\t\t\t\t})\n\t\t\t\t} else if (swipe.coordsStart.x < touchZone * 1.5 && direction === 'left') {\n\t\t\t\t\temitBusEvent('toggle-navigation', {\n\t\t\t\t\t\topen: false,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t},\n)\n\n/**\n * Size of the list pane as restored from the browser storage\n */\nconst listPaneSize = ref<number>()\n\nconst paneConfigID = computed(() => {\n\t// If provided, let's use it\n\tif (paneConfigKey !== '') {\n\t\treturn `pane-list-size-${paneConfigKey}`\n\t}\n\n\treturn `pane-list-size-${appName}`\n})\n\nconst paneDefaults = computed(() => ({\n\tlist: {\n\t\tsize: listSize,\n\t\tmin: listMinWidth,\n\t\tmax: listMaxWidth,\n\t},\n\n\t// set the inverse values of the details column\n\t// based on the provided (or default) values of the list column\n\tdetails: {\n\t\tsize: 100 - listSize,\n\t\tmin: 100 - listMaxWidth,\n\t\tmax: 100 - listMinWidth,\n\t},\n}))\n\nconst detailsPaneSize = computed(() => {\n\tif (listPaneSize.value) {\n\t\treturn 100 - listPaneSize.value\n\t}\n\treturn paneDefaults.value.details.size\n})\n\nconst realPageTitle = computed<string | null>(() => {\n\tconst entries = new Set<string>()\n\tif (pageTitle) {\n\t\t// when page title is set we only use that\n\t\t// we still split to remove duplicated instanceName\n\t\tfor (const part of pageTitle.split(' - ')) {\n\t\t\tentries.add(part)\n\t\t}\n\t} else if (pageHeading) {\n\t\t// when the page heading is provided but not the title\n\t\t// then we split to remove duplicates\n\t\t// but also add the localized app name\n\t\tfor (const part of pageHeading.split(' - ')) {\n\t\t\tentries.add(part)\n\t\t}\n\n\t\tif (entries.size > 0) {\n\t\t\tentries.add(localizedAppName)\n\t\t}\n\t} else {\n\t\treturn null\n\t}\n\n\tentries.add(instanceName)\n\treturn [...entries.values()].join(' - ')\n})\n\nwatch(realPageTitle, () => {\n\tif (realPageTitle.value !== null) {\n\t\tdocument.title = realPageTitle.value\n\t}\n}, { immediate: true })\n\nwatch(() => paneConfigKey, restorePaneConfig, { immediate: true })\n\nonMounted(restorePaneConfig)\n\n/**\n * Handle the resize of the list pane by the user.\n *\n * @param event - The `resized` event of the splitpanes component\n */\nfunction handlePaneResize(event: SplitpanesResizedEvent): void {\n\tconst size = Math.trunc(event.panes[0].size)\n\tbrowserStorage.setItem(paneConfigID.value, JSON.stringify(size))\n\tlistPaneSize.value = size\n\temit('resizeList', { size })\n\tlogger.debug('[NcAppContent] pane config', { listPaneSize: size })\n}\n\n/**\n * Restore the size of the list pane from the browser storage.\n *\n * browserStorage is not reactive, we need to update this manually.\n */\nfunction restorePaneConfig(): void {\n\tconst size = parseInt(browserStorage.getItem(paneConfigID.value) ?? '', 10)\n\tif (!isNaN(size) && size !== listPaneSize.value) {\n\t\tlogger.debug('[NcAppContent] pane config', { listPaneSize: size })\n\t\tlistPaneSize.value = size\n\t}\n}\n</script>\n\n<template>\n\t<main id=\"app-content-vue\" class=\"app-content no-snapper\" :class=\"{ 'app-content--has-list': !!$slots.list }\">\n\t\t<h1 v-if=\"pageHeading\" class=\"hidden-visually\">\n\t\t\t{{ pageHeading }}\n\t\t</h1>\n\n\t\t<template v-if=\"!!$slots.list\">\n\t\t\t<!-- Mobile view does not allow resizeable panes -->\n\t\t\t<div\n\t\t\t\tv-if=\"isMobile || layout === 'no-split'\"\n\t\t\t\tclass=\"app-content-wrapper app-content-wrapper--no-split\"\n\t\t\t\t:class=\"{\n\t\t\t\t\t'app-content-wrapper--show-details': showDetails,\n\t\t\t\t\t'app-content-wrapper--show-list': !showDetails,\n\t\t\t\t\t'app-content-wrapper--mobile': isMobile,\n\t\t\t\t}\">\n\t\t\t\t<NcAppContentDetailsToggle v-if=\"showDetails\" @click.stop.prevent=\"showDetails = false\" />\n\n\t\t\t\t<div v-show=\"!showDetails\" class=\"app-content-wrapper__list\">\n\t\t\t\t\t<slot name=\"list\" />\n\t\t\t\t</div>\n\t\t\t\t<slot v-if=\"showDetails\" />\n\t\t\t</div>\n\t\t\t<div v-else-if=\"layout === 'vertical-split' || layout === 'horizontal-split'\" class=\"app-content-wrapper\">\n\t\t\t\t<Splitpanes\n\t\t\t\t\t:horizontal=\"layout === 'horizontal-split'\"\n\t\t\t\t\tclass=\"default-theme\"\n\t\t\t\t\t:class=\"{\n\t\t\t\t\t\t'splitpanes--horizontal': layout === 'horizontal-split',\n\t\t\t\t\t\t'splitpanes--vertical': layout === 'vertical-split',\n\t\t\t\t\t}\"\n\t\t\t\t\t:rtl=\"isRtl\"\n\t\t\t\t\t@resized=\"handlePaneResize\">\n\t\t\t\t\t<Pane\n\t\t\t\t\t\tclass=\"splitpanes__pane-list\"\n\t\t\t\t\t\t:size=\"listPaneSize || paneDefaults.list.size\"\n\t\t\t\t\t\t:minSize=\"paneDefaults.list.min\"\n\t\t\t\t\t\t:maxSize=\"paneDefaults.list.max\">\n\t\t\t\t\t\t<slot name=\"list\" />\n\t\t\t\t\t</Pane>\n\n\t\t\t\t\t<Pane\n\t\t\t\t\t\tclass=\"splitpanes__pane-details\"\n\t\t\t\t\t\t:size=\"detailsPaneSize\"\n\t\t\t\t\t\t:minSize=\"paneDefaults.details.min\"\n\t\t\t\t\t\t:maxSize=\"paneDefaults.details.max\">\n\t\t\t\t\t\t<slot />\n\t\t\t\t\t</Pane>\n\t\t\t\t</Splitpanes>\n\t\t\t</div>\n\t\t</template>\n\t\t<slot v-if=\"!$slots.list\" />\n\t</main>\n</template>\n\n<style lang=\"scss\" scoped>\n\n.app-content {\n\tposition: initial;\n\tz-index: 1000;\n\tflex-basis: 100vw;\n\theight: 100%;\n\t// Overriding server styles TODO: cleanup!\n\tmargin: 0 !important;\n\tbackground-color: var(--color-main-background);\n\tmin-width: 0;\n\n\t&:not(.app-content--has-list) {\n\t\toverflow: auto;\n\t}\n}\n\n.app-content-wrapper {\n\tposition: relative;\n\twidth: 100%;\n\theight: 100%;\n}\n\n// Mobile list/details handling\n.app-content-wrapper--no-split {\n\t&.app-content-wrapper--show-list :deep() {\n\t\t.app-content-list {\n\t\t\tdisplay: flex;\n\t\t}\n\t\t.app-content-details {\n\t\t\tdisplay: none;\n\t\t}\n\t}\n\t&.app-content-wrapper--show-details :deep() {\n\t\t.app-content-list {\n\t\t\tdisplay: none;\n\t\t}\n\t\t.app-content-details {\n\t\t\tdisplay: block;\n\t\t}\n\t}\n}\n\n:deep(.splitpanes.default-theme) {\n\t.app-content-list {\n\t\tmax-width: none;\n\t\t/* Thin scrollbar is hard to catch on resizable columns */\n\t\tscrollbar-width: auto;\n\t}\n\n\t.splitpanes__pane {\n\t\tbackground-color: transparent;\n\t\ttransition: none;\n\n\t\t&-list {\n\t\t\tmin-width: 300px;\n\t\t\tposition: sticky;\n\n\t\t\t@media only screen and (width < $breakpoint-mobile) {\n\t\t\t\tdisplay: none;\n\t\t\t}\n\t\t}\n\n\t\t&-details {\n\t\t\toverflow-y: auto;\n\n\t\t\t@media only screen and (width < $breakpoint-mobile) {\n\t\t\t\tmin-width: 100%;\n\t\t\t}\n\t\t}\n\t}\n\n\t.splitpanes__splitter {\n\t\tbackground-color: var(--color-main-background);\n\t\t&::before, &::after {\n\t\t\tbackground-color: var(--color-border);\n\t\t}\n\t}\n\n\t&.splitpanes--vertical .splitpanes__splitter {\n\t\tborder-inline-start: 1px solid var(--color-border);\n\t}\n\n\t&.splitpanes--horizontal .splitpanes__splitter {\n\t\tborder-top: 1px solid var(--color-border);\n\t}\n}\n\n.app-content-wrapper--show-list {\n\t:deep(.app-content-list) {\n\t\tmax-width: none;\n\t}\n}\n\n.app-content-wrapper__list {\n\theight: 100%;\n}\n</style>\n\n<docs>\n### General description\n\nThis components provides a wrapper around the main app's content.\n\nSingle-column layouts can just use the default slot. A resizable column\ncan be added by providing content to the named slot `list`.\n\n### CSS variables\nIn the css section some css variables are declared and will be available for\nall the children of the NcAppContent component\n\n### Examples\n\n#### Usage: Single-column content\n```vue\n<template>\n\t<NcAppContent>\n\t\t<h2>Single-column main content</h2>\n\t</NcAppContent>\n</template>\n```\n\n#### Usage: Two resizable columns\n```vue\n<template>\n\t<NcAppContent>\n\t\t<template #list>\n\t\t\t<div>Resizable list content</div>\n\t\t</template>\n\n\t\t<div>Main content</div>\n\t</NcAppContent>\n</template>\n```\n\n#### Overriding Defaults\nThe default, min and max sizes (in percent) of the resizable list column can be overridden.\nThe list size must be between the min and the max width value.\n\n```\n<NcAppContent\n\t:list-size=\"35\"\n\t:list-min-width=\"20\"\n\t:list-max-width=\"45\"\n>...</NcAppContent>\n```\n\n#### Usage: Custom document title\nFor accessibility reasons every document should have a `h1` heading,\nthis is visually hidden, but required for a semantically correct document.\nYou can use your app name or current view for the heading.\n\nAdditionally you can set a custom document title, e.g. to show the current status.\n\n```vue\n<template>\n\t<NcAppContent :pageHeading=\"heading ? 'Heading' : undefined\" :pageTitle=\"title ? 'Title' : undefined\" >\n\t\t<NcCheckboxRadioSwitch type=\"switch\" :checked.sync=\"title\">\n\t\t\tToggle title\n\t\t</NcCheckboxRadioSwitch>\n\t\t<NcCheckboxRadioSwitch type=\"switch\" :checked.sync=\"heading\">\n\t\t\tToggle Heading\n\t\t</NcCheckboxRadioSwitch>\n\t\t<NcButton @click=\"reset\">Reset</NcButton>\n\t</NcAppContent>\n</template>\n\n<script>\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\theading: false,\n\t\t\ttitle: false,\n\t\t}\n\t},\n\tmethods: {\n\t\treset() {\n\t\t\tthis.heading = false\n\t\t\tthis.title = false\n\t\t\tdocument.title = ''\n\t\t},\n\t},\n}\n</script>\n```\n</docs>\n"],"names":["_createBlock","_unref","_normalizeClass","_createVNode","_useModel","emit","emitBusEvent","_createElementBlock","$slots","_toDisplayString","_Fragment","_withDirectives","_createElementVNode","_renderSlot","_openBlock"],"mappings":"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"}
|