@simple-reporting/base 1.0.28 → 1.0.30
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/dev/package.json +1 -1
- package/livingdocs/020.Text/050.quote/quote.html +6 -6
- package/livingdocs/020.Text/060.quote-with-portrait/quote-with-portrait.html +6 -6
- package/livingdocs/020.Text/060.quote-with-portrait/scss/pdf.scss +5 -0
- package/livingdocs/040.Media/010.table/scss/general.scss +3 -3
- package/livingdocs/040.Media/010.table/table.html +1 -1
- package/livingdocs/110.PDF/050.pdf-chapter-navigation-container/scss/editor.scss +1 -0
- package/package.json +1 -1
- package/plugins/viteSrlPlugin.js +7 -1
- package/scripts/build.js +71 -24
- package/scss/grid/root.scss +19 -5
- package/srl/.srl/components/Srl/Menu/Item/Content/Image/After.vue +2 -2
- package/srl/.srl/components/Srl/Menu/Item/Content/Image/Before.vue +2 -2
- package/srl/.srl/components/Srl/Menu/Item/Content/Image.vue +2 -2
- package/srl/.srl/components/Srl/Menu/Item/Content/Svg/After.vue +79 -0
- package/srl/.srl/components/Srl/Menu/Item/Content/Svg/Before.vue +79 -0
- package/srl/.srl/components/Srl/Menu/Item/Content/Svg.vue +71 -0
- package/srl/.srl/components/Srl/Menu/Item/Content.vue +18 -0
- package/srl/.srl/components/Srl/Menu/Item.vue +90 -15
- package/srl/.srl/components/Srl/Menu.vue +81 -33
- package/srl/.srl/composables/article.ts +16 -16
- package/srl/.srl/composables/articles.ts +7 -1
- package/srl/.srl/composables/index.ts +5 -0
- package/srl/.srl/composables/instance.ts +13 -0
- package/srl/.srl/composables/languageSwitch.ts +0 -3
- package/srl/.srl/plugins/initProject.ts +12 -1
- package/srl/.srl/utils/index.ts +3 -2
- package/srl/.srl/utils/uri.ts +38 -26
- /package/srl/.srl/utils/{camelCase.ts → string.ts} +0 -0
package/dev/package.json
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
<p class="srl-quote__quote srl-linkable" doc-editable="quote-text">
|
|
4
4
|
Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse
|
|
5
5
|
</p>
|
|
6
|
-
<
|
|
7
|
-
<
|
|
6
|
+
<p class="srl-quote__cite">
|
|
7
|
+
<cite class="srl-quote__name" doc-editable="quote-name" doc-optional>
|
|
8
8
|
Max Mustermann
|
|
9
|
-
</
|
|
10
|
-
<
|
|
9
|
+
</cite>
|
|
10
|
+
<span class="srl-quote__position" doc-editable="quote-position" doc-optional>
|
|
11
11
|
CEO
|
|
12
|
-
</
|
|
13
|
-
</
|
|
12
|
+
</span>
|
|
13
|
+
</p>
|
|
14
14
|
</div>
|
|
15
15
|
</blockquote>
|
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
<p class="srl-quote__quote srl-linkable" doc-editable="quote-text">
|
|
7
7
|
Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse
|
|
8
8
|
</p>
|
|
9
|
-
<
|
|
10
|
-
<
|
|
9
|
+
<p class="srl-quote__cite">
|
|
10
|
+
<cite class="srl-quote__name" doc-editable="quote-name" doc-optional>
|
|
11
11
|
Max Mustermann
|
|
12
|
-
</
|
|
13
|
-
<
|
|
12
|
+
</cite>
|
|
13
|
+
<span class="srl-quote__position" doc-editable="quote-position" doc-optional>
|
|
14
14
|
CEO
|
|
15
|
-
</
|
|
16
|
-
</
|
|
15
|
+
</span>
|
|
16
|
+
</p>
|
|
17
17
|
</div>
|
|
18
18
|
</blockquote>
|
|
@@ -270,15 +270,15 @@ td {
|
|
|
270
270
|
text-align: right;
|
|
271
271
|
}
|
|
272
272
|
|
|
273
|
-
&[class*="
|
|
273
|
+
&[class*="vatop"] {
|
|
274
274
|
vertical-align: top;
|
|
275
275
|
}
|
|
276
276
|
|
|
277
|
-
&[class*="
|
|
277
|
+
&[class*="vamiddle"] {
|
|
278
278
|
vertical-align: middle;
|
|
279
279
|
}
|
|
280
280
|
|
|
281
|
-
&[class*="
|
|
281
|
+
&[class*="vabottom"] {
|
|
282
282
|
vertical-align: bottom;
|
|
283
283
|
}
|
|
284
284
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<div class="srl-table">
|
|
2
|
-
<srl-ld-table data-remove-from-xhtml="transient" data-remove-from-pdf="transient">
|
|
2
|
+
<srl-ld-table data-replace-tag="div" data-remove-from-xhtml="transient" data-remove-from-pdf="transient">
|
|
3
3
|
<div ref="wrapper" class="srl-table__container" doc-include="nswow-table">
|
|
4
4
|
<p class="srl-grid srl-paragraph">
|
|
5
5
|
<span class="srl-grid__inner srl-paragraph__text">
|
package/package.json
CHANGED
package/plugins/viteSrlPlugin.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { join
|
|
2
|
+
import { join } from 'node:path/posix';
|
|
3
3
|
import { execSync } from 'node:child_process';
|
|
4
4
|
import folders from '../scripts/folders.js';
|
|
5
5
|
import { beaver } from '../scripts/beaver.js';
|
|
@@ -77,11 +77,17 @@ function checkForUpdates() {
|
|
|
77
77
|
try {
|
|
78
78
|
if (!data.version) return;
|
|
79
79
|
|
|
80
|
+
/*
|
|
80
81
|
const tag = `v${data.version.split('.')[0]}-lts`;
|
|
81
82
|
|
|
82
83
|
const latest = execSync(`npm view ${packageName}@${tag} version`)
|
|
83
84
|
.toString()
|
|
84
85
|
.trim();
|
|
86
|
+
*/
|
|
87
|
+
|
|
88
|
+
const latest = execSync(`npm view ${packageName} version`)
|
|
89
|
+
.toString()
|
|
90
|
+
.trim();
|
|
85
91
|
|
|
86
92
|
if (isVersionGreater(latest, data.version)) {
|
|
87
93
|
printPromptsMessage([
|
package/scripts/build.js
CHANGED
|
@@ -124,7 +124,7 @@ async function buildApp() {
|
|
|
124
124
|
return false;
|
|
125
125
|
} else {
|
|
126
126
|
src === join(folders.srlPublic, '/') ||
|
|
127
|
-
|
|
127
|
+
console.log(`Copy ${src} to ${outputPath}/app`);
|
|
128
128
|
return true;
|
|
129
129
|
}
|
|
130
130
|
},
|
|
@@ -204,13 +204,12 @@ async function buildDDev() {
|
|
|
204
204
|
buildVariables.system['size-unit'] = 'rem';
|
|
205
205
|
|
|
206
206
|
await checkFolders();
|
|
207
|
-
|
|
207
|
+
return await viteBuild({
|
|
208
208
|
build: {
|
|
209
209
|
outDir: './.output/ddev',
|
|
210
210
|
},
|
|
211
211
|
publicDir: true,
|
|
212
212
|
});
|
|
213
|
-
return build;
|
|
214
213
|
}
|
|
215
214
|
|
|
216
215
|
/**
|
|
@@ -527,7 +526,7 @@ async function buildPdfCustomer(customer) {
|
|
|
527
526
|
console.error(`Customer ${customer} does not exist in: ` + customerDir);
|
|
528
527
|
}
|
|
529
528
|
|
|
530
|
-
console.log(`\nBuild
|
|
529
|
+
console.log(`\nBuild customer ${customer}`);
|
|
531
530
|
|
|
532
531
|
const lddPdfDir = join(folders.srlOutput, 'ldd', 'pdf');
|
|
533
532
|
const lddJson = await readLivingDocsJson();
|
|
@@ -542,9 +541,10 @@ async function buildPdfCustomer(customer) {
|
|
|
542
541
|
console.error(e)
|
|
543
542
|
}
|
|
544
543
|
|
|
544
|
+
const lddXbrlDir = join(folders.srlOutput, 'ldd', 'xbrl');
|
|
545
|
+
|
|
545
546
|
try {
|
|
546
547
|
const xbrlDir = join(folders.srlOutput, 'xbrl');
|
|
547
|
-
const lddXbrlDir = join(folders.srlOutput, 'ldd', 'xbrl');
|
|
548
548
|
statSync(xbrlDir);
|
|
549
549
|
await cpSync(xbrlDir, lddXbrlDir, { recursive: true });
|
|
550
550
|
console.log(`Xbrl folder has been copied to ${relative(folders.root, lddXbrlDir)}`);
|
|
@@ -552,6 +552,49 @@ async function buildPdfCustomer(customer) {
|
|
|
552
552
|
console.error(e)
|
|
553
553
|
}
|
|
554
554
|
|
|
555
|
+
try {
|
|
556
|
+
const customerXbrlScssPath = join(customerDir, 'custom.scss');
|
|
557
|
+
const customerXbrlTarget = join(lddXbrlDir, customerName);
|
|
558
|
+
const baseXbrlScssPath = join(folders.srlImports, 'xbrl.scss');
|
|
559
|
+
|
|
560
|
+
const entries = [
|
|
561
|
+
baseXbrlScssPath,
|
|
562
|
+
customerXbrlScssPath,
|
|
563
|
+
];
|
|
564
|
+
|
|
565
|
+
buildVariables.system.environment = 'production';
|
|
566
|
+
buildVariables.system.build = 'xbrl';
|
|
567
|
+
buildVariables.system['size-unit'] = 'rem';
|
|
568
|
+
|
|
569
|
+
const config = {
|
|
570
|
+
css: {
|
|
571
|
+
preprocessorOptions: {
|
|
572
|
+
scss: {
|
|
573
|
+
api: 'modern-compiler',
|
|
574
|
+
},
|
|
575
|
+
},
|
|
576
|
+
},
|
|
577
|
+
base: './',
|
|
578
|
+
build: {
|
|
579
|
+
outDir: customerXbrlTarget,
|
|
580
|
+
lib: {
|
|
581
|
+
fileName: 'xbrl',
|
|
582
|
+
entry: entries,
|
|
583
|
+
formats: ['es'],
|
|
584
|
+
},
|
|
585
|
+
},
|
|
586
|
+
publicDir: false,
|
|
587
|
+
};
|
|
588
|
+
|
|
589
|
+
try {
|
|
590
|
+
statSync(customerXbrlScssPath)
|
|
591
|
+
await viteBuild(config);
|
|
592
|
+
} catch (e) {
|
|
593
|
+
console.error(e);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
} catch (e) {}
|
|
597
|
+
|
|
555
598
|
try {
|
|
556
599
|
const pdfDir = join(folders.srlOutput, 'pdf');
|
|
557
600
|
statSync(pdfDir);
|
|
@@ -574,6 +617,10 @@ async function buildPdfCustomer(customer) {
|
|
|
574
617
|
const tsPath = join(customerDir, 'custom.ts');
|
|
575
618
|
statSync(tsPath);
|
|
576
619
|
|
|
620
|
+
buildVariables.system.environment = 'production';
|
|
621
|
+
buildVariables.system.build = 'pdf';
|
|
622
|
+
buildVariables.system['size-unit'] = 'rem';
|
|
623
|
+
|
|
577
624
|
const config = {
|
|
578
625
|
css: {
|
|
579
626
|
preprocessorOptions: {
|
|
@@ -761,16 +808,16 @@ async function build(version, options = {}) {
|
|
|
761
808
|
const has = (name) => targets.includes(name);
|
|
762
809
|
|
|
763
810
|
if (has('ldd')) {
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
811
|
+
if (!version) {
|
|
812
|
+
const prompt = new Input({
|
|
813
|
+
message: 'Livingdocs version',
|
|
814
|
+
initial: packageJson.version,
|
|
815
|
+
});
|
|
816
|
+
version = await prompt.run();
|
|
817
|
+
}
|
|
771
818
|
|
|
772
|
-
|
|
773
|
-
|
|
819
|
+
packageJson.version = version;
|
|
820
|
+
await writePackageJson();
|
|
774
821
|
}
|
|
775
822
|
|
|
776
823
|
|
|
@@ -1015,33 +1062,33 @@ async function mapScss() {
|
|
|
1015
1062
|
await writeFileSync(
|
|
1016
1063
|
join(folders.srlImports, 'app.scss'),
|
|
1017
1064
|
`@use ` +
|
|
1018
|
-
|
|
1019
|
-
|
|
1065
|
+
output.app.join(';\n@use ') +
|
|
1066
|
+
`;\n@use "@simple-reporting/base/scss/core-styles.scss" as *;\n`,
|
|
1020
1067
|
);
|
|
1021
1068
|
await writeFileSync(
|
|
1022
1069
|
join(folders.srlImports, 'ldd.scss'),
|
|
1023
1070
|
`@use ` +
|
|
1024
|
-
|
|
1025
|
-
|
|
1071
|
+
output.ldd.join(';\n@use ') +
|
|
1072
|
+
`;\n@use "@simple-reporting/base/scss/core-styles.scss" as *;\n`,
|
|
1026
1073
|
);
|
|
1027
1074
|
await writeFileSync(
|
|
1028
1075
|
join(folders.srlImports, 'pdf.scss'),
|
|
1029
1076
|
`@use ` +
|
|
1030
|
-
|
|
1031
|
-
|
|
1077
|
+
output.pdf.join(';\n@use ') +
|
|
1078
|
+
`;\n@use "@simple-reporting/base/scss/core-styles.scss" as *;\n`,
|
|
1032
1079
|
);
|
|
1033
1080
|
await writeFileSync(
|
|
1034
1081
|
join(folders.srlImports, 'word.scss'),
|
|
1035
1082
|
`@use ` +
|
|
1036
|
-
|
|
1037
|
-
|
|
1083
|
+
output.word.join(';\n@use ') +
|
|
1084
|
+
`;\n@use "@simple-reporting/base/scss/core-styles.scss" as *;\n`,
|
|
1038
1085
|
);
|
|
1039
1086
|
|
|
1040
1087
|
await writeFileSync(
|
|
1041
1088
|
join(folders.srlImports, 'xbrl.scss'),
|
|
1042
1089
|
`@use ` +
|
|
1043
|
-
|
|
1044
|
-
|
|
1090
|
+
output.xbrl.join(`;\n@use `) +
|
|
1091
|
+
`;\n@use "@simple-reporting/base/scss/xbrl-core-styles.scss" as *;\n`,
|
|
1045
1092
|
);
|
|
1046
1093
|
|
|
1047
1094
|
return true;
|
package/scss/grid/root.scss
CHANGED
|
@@ -2,7 +2,21 @@
|
|
|
2
2
|
@use "../system";
|
|
3
3
|
@use "sass:map";
|
|
4
4
|
|
|
5
|
+
$smallest-breakpoint: null;
|
|
6
|
+
|
|
7
|
+
@each $breakpoint, $min-width in variables.$breakpoints {
|
|
8
|
+
@if $min-width == 0 {
|
|
9
|
+
$smallest-breakpoint: $breakpoint;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
5
13
|
@each $breakpoint, $min-width in variables.$breakpoints {
|
|
14
|
+
$breakpoint-map: $breakpoint;
|
|
15
|
+
|
|
16
|
+
@if $breakpoint == $smallest-breakpoint {
|
|
17
|
+
$breakpoint-map: false;
|
|
18
|
+
}
|
|
19
|
+
|
|
6
20
|
$size-unit: false;
|
|
7
21
|
@if $breakpoint == print {
|
|
8
22
|
$size-unit: in;
|
|
@@ -23,7 +37,7 @@
|
|
|
23
37
|
@include system.add-root-style(
|
|
24
38
|
#{variables.$variable-prefix}container-max-width,
|
|
25
39
|
system.size-unit($container-max-width, $size-unit),
|
|
26
|
-
$breakpoint
|
|
40
|
+
$breakpoint-map
|
|
27
41
|
);
|
|
28
42
|
|
|
29
43
|
$container-padding: map.get($container, padding);
|
|
@@ -34,7 +48,7 @@
|
|
|
34
48
|
@include system.add-root-style(
|
|
35
49
|
#{variables.$variable-prefix}container-padding,
|
|
36
50
|
system.size-unit($container-padding, $size-unit),
|
|
37
|
-
$breakpoint
|
|
51
|
+
$breakpoint-map
|
|
38
52
|
);
|
|
39
53
|
|
|
40
54
|
$gutter: map.get(variables.$gutter, $breakpoint);
|
|
@@ -64,17 +78,17 @@
|
|
|
64
78
|
@include system.add-root-style(
|
|
65
79
|
#{variables.$variable-prefix}gutter-columns,
|
|
66
80
|
$columns,
|
|
67
|
-
$breakpoint
|
|
81
|
+
$breakpoint-map
|
|
68
82
|
);
|
|
69
83
|
@include system.add-root-style(
|
|
70
84
|
#{variables.$variable-prefix}gutter-row-gap,
|
|
71
85
|
system.size-unit($row-gap, $size-unit),
|
|
72
|
-
$breakpoint
|
|
86
|
+
$breakpoint-map
|
|
73
87
|
);
|
|
74
88
|
|
|
75
89
|
@include system.add-root-style(
|
|
76
90
|
#{variables.$variable-prefix}gutter-column-gap,
|
|
77
91
|
system.size-unit($column-gap, $size-unit),
|
|
78
|
-
$breakpoint
|
|
92
|
+
$breakpoint-map
|
|
79
93
|
);
|
|
80
94
|
}
|
|
@@ -26,7 +26,7 @@ const classListText = computed(() => {
|
|
|
26
26
|
<span :class="classListText" v-text="props.item.label"/>
|
|
27
27
|
<img
|
|
28
28
|
:class="classListIcon"
|
|
29
|
-
:src="props.item.imgAfter
|
|
30
|
-
:alt="props.item.imgAfter
|
|
29
|
+
:src="props.item.imgAfter?.src"
|
|
30
|
+
:alt="props.item.imgAfter?.alt ?? props.item.label"
|
|
31
31
|
/>
|
|
32
32
|
</template>
|
|
@@ -25,8 +25,8 @@ const classListText = computed(() => {
|
|
|
25
25
|
<template>
|
|
26
26
|
<img
|
|
27
27
|
:class="classListIcon"
|
|
28
|
-
:src="props.item.imgBefore
|
|
29
|
-
:alt="props.item.imgBefore
|
|
28
|
+
:src="props.item.imgBefore?.src"
|
|
29
|
+
:alt="props.item.imgBefore?.alt ?? props.item.label"
|
|
30
30
|
/>
|
|
31
31
|
<span :class="classListText" v-text="props.item.label"/>
|
|
32
32
|
</template>
|
|
@@ -18,7 +18,7 @@ const classListIcon = computed(() => {
|
|
|
18
18
|
<template>
|
|
19
19
|
<img
|
|
20
20
|
:class="classListIcon"
|
|
21
|
-
:src="props.item.img
|
|
22
|
-
:alt="props.item.img
|
|
21
|
+
:src="props.item.img?.src"
|
|
22
|
+
:alt="props.item.img?.alt ?? props.item.label"
|
|
23
23
|
/>
|
|
24
24
|
</template>
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, watch, computed, h, type VNode } from 'vue'
|
|
3
|
+
|
|
4
|
+
const props = defineProps<{
|
|
5
|
+
item: NsWowNavigationItem
|
|
6
|
+
depth: number
|
|
7
|
+
disableClasses: boolean
|
|
8
|
+
}>();
|
|
9
|
+
|
|
10
|
+
const classListIcon = computed(() => {
|
|
11
|
+
return props.disableClasses ? [] : [
|
|
12
|
+
'srl-menu__link-svg-after',
|
|
13
|
+
`srl-menu__link-svg-after--level-${props.depth}`
|
|
14
|
+
]
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
const svgVNode = ref<VNode | null>(null)
|
|
18
|
+
|
|
19
|
+
watch(
|
|
20
|
+
props,
|
|
21
|
+
async (to) => {
|
|
22
|
+
if (typeof to.item.svgAfter === 'string') {
|
|
23
|
+
let icon
|
|
24
|
+
if (to.item.svgAfter.startsWith('data:image/svg+xml,')) {
|
|
25
|
+
icon = decodeURIComponent(to.item.svgAfter.replace('data:image/svg+xml,', ''))
|
|
26
|
+
} else if (!to.item.svgAfter.startsWith('<svg')) {
|
|
27
|
+
try {
|
|
28
|
+
const res = await fetch(to.item.svgAfter)
|
|
29
|
+
if (!res.ok) {
|
|
30
|
+
svgVNode.value = null
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
icon = await res.text()
|
|
34
|
+
} catch (e) {
|
|
35
|
+
svgVNode.value = null
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
icon = to.item.svgAfter
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!icon) {
|
|
43
|
+
svgVNode.value = null
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
const parser = new DOMParser()
|
|
47
|
+
const doc = parser.parseFromString(icon, 'image/svg+xml')
|
|
48
|
+
const svg = doc.querySelector('svg')
|
|
49
|
+
if (!svg) {
|
|
50
|
+
svgVNode.value = null
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const attrs = Object.fromEntries([...svg.attributes].map(attr => [attr.name, attr.value]))
|
|
55
|
+
|
|
56
|
+
svgVNode.value = h('svg', {
|
|
57
|
+
innerHTML: svg.innerHTML,
|
|
58
|
+
...attrs
|
|
59
|
+
})
|
|
60
|
+
} else {
|
|
61
|
+
svgVNode.value = null
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
{ immediate: true }
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
const classListText = computed(() => {
|
|
68
|
+
return props.disableClasses ? [] : [
|
|
69
|
+
'srl-menu__link-text',
|
|
70
|
+
`srl-menu__link-text--level-${props.depth}`
|
|
71
|
+
]
|
|
72
|
+
})
|
|
73
|
+
</script>
|
|
74
|
+
|
|
75
|
+
<template>
|
|
76
|
+
<span :class="classListText" v-text="props.item.label"/>
|
|
77
|
+
<component :is="svgVNode" v-if="svgVNode" :class="classListIcon" />
|
|
78
|
+
<component :is="props.item.svgAfter" v-if="typeof props.item.svgAfter === 'object'" :class="classListIcon" />
|
|
79
|
+
</template>
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, watch, computed, h, type VNode } from 'vue'
|
|
3
|
+
|
|
4
|
+
const props = defineProps<{
|
|
5
|
+
item: NsWowNavigationItem
|
|
6
|
+
depth: number
|
|
7
|
+
disableClasses: boolean
|
|
8
|
+
}>();
|
|
9
|
+
|
|
10
|
+
const classListIcon = computed(() => {
|
|
11
|
+
return props.disableClasses ? [] : [
|
|
12
|
+
'srl-menu__link-svg-before',
|
|
13
|
+
`srl-menu__link-svg-before--level-${props.depth}`
|
|
14
|
+
]
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
const svgVNode = ref<VNode | null>(null)
|
|
18
|
+
|
|
19
|
+
watch(
|
|
20
|
+
props,
|
|
21
|
+
async (to) => {
|
|
22
|
+
if (typeof to.item.svgBefore === 'string') {
|
|
23
|
+
let icon
|
|
24
|
+
if (to.item.svgBefore.startsWith('data:image/svg+xml,')) {
|
|
25
|
+
icon = decodeURIComponent(to.item.svgBefore.replace('data:image/svg+xml,', ''))
|
|
26
|
+
} else if (!to.item.svgBefore.startsWith('<svg')) {
|
|
27
|
+
try {
|
|
28
|
+
const res = await fetch(to.item.svgBefore)
|
|
29
|
+
if (!res.ok) {
|
|
30
|
+
svgVNode.value = null
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
icon = await res.text()
|
|
34
|
+
} catch (e) {
|
|
35
|
+
svgVNode.value = null
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
icon = to.item.svgBefore
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!icon) {
|
|
43
|
+
svgVNode.value = null
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
const parser = new DOMParser()
|
|
47
|
+
const doc = parser.parseFromString(icon, 'image/svg+xml')
|
|
48
|
+
const svg = doc.querySelector('svg')
|
|
49
|
+
if (!svg) {
|
|
50
|
+
svgVNode.value = null
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const attrs = Object.fromEntries([...svg.attributes].map(attr => [attr.name, attr.value]))
|
|
55
|
+
|
|
56
|
+
svgVNode.value = h('svg', {
|
|
57
|
+
innerHTML: svg.innerHTML,
|
|
58
|
+
...attrs
|
|
59
|
+
})
|
|
60
|
+
} else {
|
|
61
|
+
svgVNode.value = null
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
{ immediate: true }
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
const classListText = computed(() => {
|
|
68
|
+
return props.disableClasses ? [] : [
|
|
69
|
+
'srl-menu__link-text',
|
|
70
|
+
`srl-menu__link-text--level-${props.depth}`
|
|
71
|
+
]
|
|
72
|
+
})
|
|
73
|
+
</script>
|
|
74
|
+
|
|
75
|
+
<template>
|
|
76
|
+
<component :is="svgVNode" v-if="svgVNode" :class="classListIcon" />
|
|
77
|
+
<component :is="props.item.svgBefore" v-else-if="typeof props.item.svgBefore === 'object'" :class="classListIcon" />
|
|
78
|
+
<span :class="classListText" v-text="props.item.label"/>
|
|
79
|
+
</template>
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, watch, computed, h, type VNode } from 'vue'
|
|
3
|
+
|
|
4
|
+
const props = defineProps<{
|
|
5
|
+
item: NsWowNavigationItem
|
|
6
|
+
depth: number
|
|
7
|
+
disableClasses: boolean
|
|
8
|
+
}>();
|
|
9
|
+
|
|
10
|
+
const classListIcon = computed(() => {
|
|
11
|
+
return props.disableClasses ? [] : [
|
|
12
|
+
'srl-menu__link-svg',
|
|
13
|
+
`srl-menu__link-svg--level-${props.depth}`
|
|
14
|
+
]
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
const svgVNode = ref<VNode | null>(null)
|
|
18
|
+
|
|
19
|
+
watch(
|
|
20
|
+
props,
|
|
21
|
+
async (to) => {
|
|
22
|
+
if (typeof to.item.svg === 'string') {
|
|
23
|
+
let icon
|
|
24
|
+
if (to.item.svg.startsWith('data:image/svg+xml,')) {
|
|
25
|
+
icon = decodeURIComponent(to.item.svg.replace('data:image/svg+xml,', ''))
|
|
26
|
+
} else if (!to.item.svg.startsWith('<svg')) {
|
|
27
|
+
try {
|
|
28
|
+
const res = await fetch(icon)
|
|
29
|
+
if (!res.ok) {
|
|
30
|
+
svgVNode.value = null
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
icon = await res.text()
|
|
34
|
+
} catch (e) {
|
|
35
|
+
svgVNode.value = null
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
icon = to.item.svg
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!icon) {
|
|
43
|
+
svgVNode.value = null
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
const parser = new DOMParser()
|
|
47
|
+
const doc = parser.parseFromString(icon, 'image/svg+xml')
|
|
48
|
+
const svg = doc.querySelector('svg')
|
|
49
|
+
if (!svg) {
|
|
50
|
+
svgVNode.value = null
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const attrs = Object.fromEntries([...svg.attributes].map(attr => [attr.name, attr.value]))
|
|
55
|
+
|
|
56
|
+
svgVNode.value = h('svg', {
|
|
57
|
+
innerHTML: svg.innerHTML,
|
|
58
|
+
...attrs
|
|
59
|
+
})
|
|
60
|
+
} else {
|
|
61
|
+
svgVNode.value = null
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
{ immediate: true }
|
|
65
|
+
)
|
|
66
|
+
</script>
|
|
67
|
+
|
|
68
|
+
<template>
|
|
69
|
+
<component :is="svgVNode" v-if="svgVNode" :class="classListIcon" />
|
|
70
|
+
<component :is="props.item.svg" v-else-if="typeof props.item.svg === 'object'" :class="classListIcon" />
|
|
71
|
+
</template>
|
|
@@ -44,6 +44,24 @@ const props = defineProps<{
|
|
|
44
44
|
:depth="props.depth"
|
|
45
45
|
:disableClasses="props.disableClasses"
|
|
46
46
|
/>
|
|
47
|
+
<SrlMenuItemContentSvg
|
|
48
|
+
v-else-if="props.item.svg"
|
|
49
|
+
:item="props.item"
|
|
50
|
+
:depth="props.depth"
|
|
51
|
+
:disableClasses="props.disableClasses"
|
|
52
|
+
/>
|
|
53
|
+
<SrlMenuItemContentSvgBefore
|
|
54
|
+
v-else-if="props.item.svgBefore"
|
|
55
|
+
:item="props.item"
|
|
56
|
+
:depth="props.depth"
|
|
57
|
+
:disableClasses="props.disableClasses"
|
|
58
|
+
/>
|
|
59
|
+
<SrlMenuItemContentSvgAfter
|
|
60
|
+
v-else-if="props.item.svgAfter"
|
|
61
|
+
:item="props.item"
|
|
62
|
+
:depth="props.depth"
|
|
63
|
+
:disableClasses="props.disableClasses"
|
|
64
|
+
/>
|
|
47
65
|
<SrlMenuItemContentText
|
|
48
66
|
v-else
|
|
49
67
|
:item="props.item"
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed, nextTick, ref, useId } from 'vue'
|
|
2
|
+
import { computed, nextTick, ref, useId, VNode } from 'vue'
|
|
3
|
+
import type { Ref } from 'vue'
|
|
3
4
|
import type { RouterLink } from 'vue-router'
|
|
4
5
|
import { isExternalPath } from '#utils/uri'
|
|
5
6
|
|
|
@@ -17,6 +18,12 @@ type BackButtonItem = {
|
|
|
17
18
|
src: string
|
|
18
19
|
alt?: string
|
|
19
20
|
}
|
|
21
|
+
icon?: string
|
|
22
|
+
iconBefore?: string
|
|
23
|
+
iconAfter?: string
|
|
24
|
+
svg?: VNode | string;
|
|
25
|
+
svgBefore?: VNode | string;
|
|
26
|
+
svgAfter?: VNode | string;
|
|
20
27
|
attributes?: {
|
|
21
28
|
[key: string]: string
|
|
22
29
|
}
|
|
@@ -31,12 +38,19 @@ const props = defineProps<{
|
|
|
31
38
|
initOpen: number
|
|
32
39
|
depth: number
|
|
33
40
|
disableClasses: boolean
|
|
34
|
-
|
|
35
|
-
backButtonLabel
|
|
36
|
-
backButtonItem
|
|
41
|
+
backButtonEnabled: boolean
|
|
42
|
+
backButtonLabel: (backPath: NsWowNavigationItem[]) => string
|
|
43
|
+
backButtonItem?: BackButtonItem
|
|
44
|
+
backPath: NsWowNavigationItem[]
|
|
45
|
+
path: NsWowNavigationItem[]
|
|
37
46
|
}>()
|
|
38
47
|
|
|
48
|
+
const breadcrumb = defineModel<NsWowNavigationItem[]>('breadcrumb', {
|
|
49
|
+
required: true,
|
|
50
|
+
}) as Ref<NsWowNavigationItem[]>
|
|
51
|
+
|
|
39
52
|
const emit = defineEmits([
|
|
53
|
+
'toggle',
|
|
40
54
|
'open',
|
|
41
55
|
'close',
|
|
42
56
|
'link',
|
|
@@ -51,15 +65,43 @@ if (props.item.children) {
|
|
|
51
65
|
id.value = useId()
|
|
52
66
|
}
|
|
53
67
|
|
|
68
|
+
const currentBackPath = computed<NsWowNavigationItem[]>(() => {
|
|
69
|
+
if (!props.item?.attributes?.class?.includes('srl-menu__link--back')) {
|
|
70
|
+
const i: NsWowNavigationItem = {
|
|
71
|
+
label: props.item.label
|
|
72
|
+
}
|
|
73
|
+
props.item.title ? i.title = props.item.title : null
|
|
74
|
+
props.item.img ? i.img = props.item.img : null
|
|
75
|
+
props.item.imgBefore ? i.imgBefore = props.item.imgBefore : null
|
|
76
|
+
props.item.imgAfter ? i.imgAfter = props.item.imgAfter : null
|
|
77
|
+
props.item.icon ? i.icon = props.item.icon : null
|
|
78
|
+
props.item.iconBefore ? i.iconBefore = props.item.iconBefore : null
|
|
79
|
+
props.item.iconAfter ? i.iconAfter = props.item.iconAfter : null
|
|
80
|
+
props.item.svg ? i.svg = props.item.svg : null
|
|
81
|
+
props.item.svgBefore ? i.svgBefore = props.item.svgBefore : null
|
|
82
|
+
props.item.svgAfter ? i.svgAfter = props.item.svgAfter : null
|
|
83
|
+
props.item.attributes ? i.attributes = props.item.attributes : null
|
|
84
|
+
return [i, ...props.backPath]
|
|
85
|
+
}
|
|
86
|
+
return props.backPath
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
const currentPath = computed<NsWowNavigationItem[]>(() => {
|
|
90
|
+
return [...props.path, props.item]
|
|
91
|
+
})
|
|
92
|
+
|
|
54
93
|
const external = ref(props.item.href && isExternalPath(props.item.href))
|
|
55
94
|
|
|
56
95
|
const menu = ref()
|
|
57
|
-
const $el = ref<
|
|
96
|
+
const $el = ref<HTMLElement | null>(null)
|
|
58
97
|
const opened = ref(false)
|
|
59
98
|
|
|
60
|
-
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
function toggleAction() {
|
|
61
102
|
opened.value = !opened.value
|
|
62
103
|
if (opened.value) {
|
|
104
|
+
breadcrumb.value = currentPath.value
|
|
63
105
|
emit('open', { index: props.index })
|
|
64
106
|
nextTick(() => {
|
|
65
107
|
menu.value.$el.focus()
|
|
@@ -67,13 +109,22 @@ function toggle() {
|
|
|
67
109
|
} else {
|
|
68
110
|
menu.value.closeAll()
|
|
69
111
|
}
|
|
112
|
+
toggle()
|
|
70
113
|
}
|
|
71
114
|
function close() {
|
|
115
|
+
breadcrumb.value = props.path
|
|
72
116
|
emit('close', { index: props.index })
|
|
73
117
|
}
|
|
74
118
|
|
|
75
119
|
function closeSub() {
|
|
76
|
-
|
|
120
|
+
breadcrumb.value = props.path
|
|
121
|
+
if ($el.value instanceof HTMLElement) {
|
|
122
|
+
$el.value.focus()
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function toggle() {
|
|
127
|
+
emit('toggle')
|
|
77
128
|
}
|
|
78
129
|
|
|
79
130
|
function next() {
|
|
@@ -99,6 +150,7 @@ function back(event: KeyboardEvent) {
|
|
|
99
150
|
event.preventDefault()
|
|
100
151
|
}
|
|
101
152
|
emit('back')
|
|
153
|
+
toggle()
|
|
102
154
|
}
|
|
103
155
|
|
|
104
156
|
function link() {
|
|
@@ -113,23 +165,41 @@ function routerChange() {
|
|
|
113
165
|
}
|
|
114
166
|
|
|
115
167
|
function closeItem() {
|
|
168
|
+
!opened.value || toggle()
|
|
116
169
|
opened.value = false
|
|
117
170
|
menu.value?.closeAll()
|
|
118
171
|
}
|
|
119
172
|
|
|
173
|
+
function findPath(): NsWowNavigationItem[] | null {
|
|
174
|
+
if (opened.value) {
|
|
175
|
+
if (props.item?.children?.length) {
|
|
176
|
+
let res = [...props.path, props.item]
|
|
177
|
+
menu.value.items.forEach((item) => {
|
|
178
|
+
item.opened && (res = item.findPath() || res)
|
|
179
|
+
})
|
|
180
|
+
return res
|
|
181
|
+
} else {
|
|
182
|
+
return currentPath.value
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return null
|
|
186
|
+
}
|
|
187
|
+
|
|
120
188
|
defineExpose({
|
|
189
|
+
opened,
|
|
121
190
|
closeItem,
|
|
191
|
+
findPath,
|
|
122
192
|
$el,
|
|
123
193
|
menu,
|
|
124
194
|
})
|
|
125
195
|
|
|
126
|
-
function internalLinkClick(
|
|
127
|
-
!props.item.callback || props.item.callback(
|
|
196
|
+
function internalLinkClick() {
|
|
197
|
+
!props.item.callback || props.item.callback()
|
|
128
198
|
routerChange()
|
|
129
199
|
}
|
|
130
200
|
|
|
131
|
-
function externalLinkClick(
|
|
132
|
-
!props.item.callback || props.item.callback(
|
|
201
|
+
function externalLinkClick() {
|
|
202
|
+
!props.item.callback || props.item.callback()
|
|
133
203
|
link()
|
|
134
204
|
}
|
|
135
205
|
|
|
@@ -258,7 +328,7 @@ const classListItem = computed(() => {
|
|
|
258
328
|
:title="props.item.title ?? props.item.label"
|
|
259
329
|
:aria-label="props.item.icon ? props.item.title ?? props.item.label : undefined"
|
|
260
330
|
v-bind="dynamicAttributes"
|
|
261
|
-
@click.stop="
|
|
331
|
+
@click.stop="toggleAction"
|
|
262
332
|
@keydown.left.stop.prevent="prev"
|
|
263
333
|
@keydown.up.stop.prevent="prev"
|
|
264
334
|
@keydown.down.stop.prevent="next"
|
|
@@ -276,6 +346,9 @@ const classListItem = computed(() => {
|
|
|
276
346
|
<SrlMenu
|
|
277
347
|
v-if="props.item.children"
|
|
278
348
|
ref="menu"
|
|
349
|
+
:key="id"
|
|
350
|
+
v-model:opened="opened"
|
|
351
|
+
v-model:breadcrumb="breadcrumb"
|
|
279
352
|
:id="`${props.name}-${id}`"
|
|
280
353
|
:name="props.name"
|
|
281
354
|
:menu="props.item.children"
|
|
@@ -283,14 +356,16 @@ const classListItem = computed(() => {
|
|
|
283
356
|
:initOpen="props.initOpen"
|
|
284
357
|
:depth="props.depth + 1"
|
|
285
358
|
:disableClasses="props.disableClasses"
|
|
286
|
-
:
|
|
287
|
-
:backButtonLabel="props.
|
|
359
|
+
:backButtonEnabled="props.backButtonEnabled"
|
|
360
|
+
:backButtonLabel="props.backButtonLabel"
|
|
288
361
|
:backButtonItem="props.backButtonItem"
|
|
289
|
-
|
|
362
|
+
:path="currentPath"
|
|
363
|
+
:backPath="currentBackPath"
|
|
290
364
|
@link="link"
|
|
291
365
|
@routerChange="emit('routerChange')"
|
|
292
366
|
@tab="tab"
|
|
293
367
|
@closeSub="closeSub"
|
|
368
|
+
@toggle="toggle"
|
|
294
369
|
/>
|
|
295
370
|
</li>
|
|
296
371
|
</template>
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
* @link="handleNavigation"
|
|
51
51
|
* />
|
|
52
52
|
*/
|
|
53
|
-
import { computed, ref } from 'vue'
|
|
53
|
+
import { computed, ref, VNode } from 'vue'
|
|
54
54
|
|
|
55
55
|
type BackButtonItem = {
|
|
56
56
|
title?: string
|
|
@@ -66,6 +66,12 @@ type BackButtonItem = {
|
|
|
66
66
|
src: string
|
|
67
67
|
alt?: string
|
|
68
68
|
}
|
|
69
|
+
icon?: string
|
|
70
|
+
iconBefore?: string
|
|
71
|
+
iconAfter?: string
|
|
72
|
+
svg?: VNode | string;
|
|
73
|
+
svgBefore?: VNode | string;
|
|
74
|
+
svgAfter?: VNode | string;
|
|
69
75
|
attributes?: {
|
|
70
76
|
[key: string]: string
|
|
71
77
|
}
|
|
@@ -82,9 +88,11 @@ const props = withDefaults(
|
|
|
82
88
|
singleOpen?: boolean
|
|
83
89
|
depth?: number
|
|
84
90
|
disableClasses?: boolean
|
|
85
|
-
|
|
91
|
+
backButtonEnabled?: boolean
|
|
92
|
+
backButtonLabel?: (backPath: NsWowNavigationItem[]) => string
|
|
86
93
|
backButtonItem?: BackButtonItem
|
|
87
|
-
|
|
94
|
+
path?: NsWowNavigationItem[]
|
|
95
|
+
backPath?: NsWowNavigationItem[]
|
|
88
96
|
}>(),
|
|
89
97
|
{
|
|
90
98
|
disableTab: false,
|
|
@@ -93,11 +101,15 @@ const props = withDefaults(
|
|
|
93
101
|
singleOpen: true,
|
|
94
102
|
depth: 0,
|
|
95
103
|
disableClasses: false,
|
|
96
|
-
|
|
104
|
+
backButtonLabel: function(backPath: NsWowNavigationItem[]) {
|
|
105
|
+
return backPath[0]?
|
|
106
|
+
backPath[0]?.label ?? 'Back' : 'Back'
|
|
107
|
+
},
|
|
97
108
|
},
|
|
98
109
|
)
|
|
99
110
|
|
|
100
111
|
const emit = defineEmits([
|
|
112
|
+
'toggle',
|
|
101
113
|
'close',
|
|
102
114
|
'closeSub',
|
|
103
115
|
'link',
|
|
@@ -110,6 +122,10 @@ const emit = defineEmits([
|
|
|
110
122
|
const items = ref<SrlMenuItem[]>([])
|
|
111
123
|
|
|
112
124
|
const opened = defineModel('opened', { type: Boolean, default: true })
|
|
125
|
+
const breadcrumb = defineModel('breadcrumb', {
|
|
126
|
+
type: Array,
|
|
127
|
+
default: [],
|
|
128
|
+
})
|
|
113
129
|
|
|
114
130
|
function open(event: { index: number }) {
|
|
115
131
|
if (props.singleOpen) {
|
|
@@ -124,6 +140,7 @@ function close() {
|
|
|
124
140
|
} else {
|
|
125
141
|
emit('close')
|
|
126
142
|
}
|
|
143
|
+
toggle()
|
|
127
144
|
}
|
|
128
145
|
|
|
129
146
|
function next(event: { index: number }) {
|
|
@@ -166,10 +183,27 @@ function routerChange() {
|
|
|
166
183
|
emit('routerChange')
|
|
167
184
|
}
|
|
168
185
|
|
|
186
|
+
function toggle() {
|
|
187
|
+
emit('toggle')
|
|
188
|
+
}
|
|
189
|
+
|
|
169
190
|
function closeAll(keep?: number | string) {
|
|
191
|
+
let findCurrentPath = null
|
|
170
192
|
items.value.forEach((item: SrlMenuItem, index: number) => {
|
|
171
|
-
if (keep !== index)
|
|
193
|
+
if (keep !== index) {
|
|
194
|
+
item.closeItem()
|
|
195
|
+
}
|
|
196
|
+
const currentPath = item.findPath()
|
|
197
|
+
if (currentPath) {
|
|
198
|
+
findCurrentPath = currentPath
|
|
199
|
+
}
|
|
172
200
|
})
|
|
201
|
+
if (findCurrentPath) {
|
|
202
|
+
breadcrumb.value = findCurrentPath
|
|
203
|
+
} else {
|
|
204
|
+
breadcrumb.value = props.path && props.path.length ?
|
|
205
|
+
props.path.slice(0, -1) : []
|
|
206
|
+
}
|
|
173
207
|
}
|
|
174
208
|
|
|
175
209
|
const $el = ref<HTMLUListElement>()
|
|
@@ -186,36 +220,44 @@ function focusClickable(index: number) {
|
|
|
186
220
|
|
|
187
221
|
const menuItems = computed<NsWowNavigationItem[]>(() => {
|
|
188
222
|
const classes: string[] = []
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
223
|
+
const backButtonAttributes = props.backButtonItem?.attributes
|
|
224
|
+
if (backButtonAttributes && backButtonAttributes.class.length > 0) {
|
|
225
|
+
backButtonAttributes.class.split(' ').forEach(c => {
|
|
226
|
+
if (c) classes.push(c)
|
|
192
227
|
})
|
|
193
228
|
}
|
|
194
229
|
classes.push('srl-menu__link--back')
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
...props.
|
|
218
|
-
|
|
230
|
+
|
|
231
|
+
let backLabel: string = props.backButtonLabel(props.backPath ?? [])
|
|
232
|
+
|
|
233
|
+
if
|
|
234
|
+
(props.backButtonEnabled &&
|
|
235
|
+
props.depth &&
|
|
236
|
+
props.backButtonItem
|
|
237
|
+
) {
|
|
238
|
+
const backItem: NsWowNavigationItem = {
|
|
239
|
+
label: backLabel,
|
|
240
|
+
}
|
|
241
|
+
props.backButtonItem.title ? backItem.title = props.backButtonItem.title : null
|
|
242
|
+
props.backButtonItem.img ? backItem.img = props.backButtonItem.img : null
|
|
243
|
+
props.backButtonItem.imgBefore ? backItem.imgBefore = props.backButtonItem.imgBefore : null
|
|
244
|
+
props.backButtonItem.imgAfter ? backItem.imgAfter = props.backButtonItem.imgAfter : null
|
|
245
|
+
props.backButtonItem.icon ? backItem.icon = props.backButtonItem.icon : null
|
|
246
|
+
props.backButtonItem.iconBefore ? backItem.iconBefore = props.backButtonItem.iconBefore : null
|
|
247
|
+
props.backButtonItem.iconAfter ? backItem.iconAfter = props.backButtonItem.iconAfter : null
|
|
248
|
+
props.backButtonItem.svg ? backItem.svg = props.backButtonItem.svg : null
|
|
249
|
+
props.backButtonItem.svgBefore ? backItem.svgBefore = props.backButtonItem.svgBefore : null
|
|
250
|
+
props.backButtonItem.svgAfter ? backItem.svgAfter = props.backButtonItem.svgAfter : null
|
|
251
|
+
backItem.attributes = {
|
|
252
|
+
...(props.backButtonItem.attributes ?? {}),
|
|
253
|
+
class: classes.join(' '),
|
|
254
|
+
'aria-controls': props.id ?? '',
|
|
255
|
+
'aria-expanded': String(opened.value)
|
|
256
|
+
}
|
|
257
|
+
backItem.callback = close
|
|
258
|
+
return [backItem, ...props.menu]
|
|
259
|
+
}
|
|
260
|
+
return props.menu
|
|
219
261
|
})
|
|
220
262
|
|
|
221
263
|
const classList = computed(() => {
|
|
@@ -229,7 +271,9 @@ defineExpose({
|
|
|
229
271
|
closeAll,
|
|
230
272
|
$el,
|
|
231
273
|
items,
|
|
274
|
+
breadcrumb,
|
|
232
275
|
})
|
|
276
|
+
|
|
233
277
|
</script>
|
|
234
278
|
|
|
235
279
|
<template>
|
|
@@ -249,6 +293,7 @@ defineExpose({
|
|
|
249
293
|
<template v-for="(item, index) in menuItems" :key="index">
|
|
250
294
|
<SrlMenuItem
|
|
251
295
|
ref="items"
|
|
296
|
+
v-model:breadcrumb="breadcrumb"
|
|
252
297
|
:item="item"
|
|
253
298
|
:name="props.name"
|
|
254
299
|
:index="index"
|
|
@@ -257,9 +302,11 @@ defineExpose({
|
|
|
257
302
|
:initOpen="props.initOpen"
|
|
258
303
|
:depth="props.depth"
|
|
259
304
|
:disableClasses="props.disableClasses"
|
|
260
|
-
:
|
|
305
|
+
:backButtonEnabled="props.backButtonEnabled"
|
|
261
306
|
:backButtonLabel="props.backButtonLabel"
|
|
262
307
|
:backButtonItem="props.backButtonItem"
|
|
308
|
+
:path="props.path ?? []"
|
|
309
|
+
:backPath="props.backPath ?? []"
|
|
263
310
|
@open="open"
|
|
264
311
|
@close="close"
|
|
265
312
|
@next="next"
|
|
@@ -268,6 +315,7 @@ defineExpose({
|
|
|
268
315
|
@back="back"
|
|
269
316
|
@link="link"
|
|
270
317
|
@routerChange="routerChange"
|
|
318
|
+
@toggle="toggle"
|
|
271
319
|
/>
|
|
272
320
|
</template>
|
|
273
321
|
</ul>
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
import { computed, type ComputedRef } from 'vue';
|
|
2
|
-
import {
|
|
2
|
+
import { useInstance } from '#composables/instance.ts'
|
|
3
3
|
import useArticles from './articles';
|
|
4
4
|
|
|
5
5
|
const articles = useArticles();
|
|
6
|
+
const instance = useInstance();
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
: undefined;
|
|
13
|
-
const article = !slug
|
|
14
|
-
? articles.value.find((article) => article.index)
|
|
15
|
-
: articles.value.find((article) => article.slug === slug);
|
|
8
|
+
const slug = computed(() => {
|
|
9
|
+
return instance.value?.config.globalProperties.$route?.params?.slug
|
|
10
|
+
? (instance.value?.config.globalProperties.$route?.params?.slug[0] as string)
|
|
11
|
+
: undefined;
|
|
12
|
+
});
|
|
16
13
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
const article = computed<NsWowArticle | undefined>(() => {
|
|
15
|
+
const slugValue = slug.value;
|
|
16
|
+
const a = articles.value
|
|
17
|
+
return !slugValue
|
|
18
|
+
? a.find((article) => article.index)
|
|
19
|
+
: a.find((article) => article.slug === slugValue);
|
|
20
|
+
});
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
export default function useArticle(): ComputedRef<NsWowArticle | undefined> {
|
|
23
|
+
return article;
|
|
24
24
|
}
|
|
@@ -29,11 +29,17 @@
|
|
|
29
29
|
*/
|
|
30
30
|
import { computed, type ComputedRef } from 'vue';
|
|
31
31
|
import useConfig from './config.ts';
|
|
32
|
+
import { useInstance } from '#composables/instance.ts';
|
|
32
33
|
|
|
33
34
|
const config = useConfig();
|
|
35
|
+
const instance = useInstance();
|
|
36
|
+
const locale = computed(() => instance.value?.config.globalProperties.$route.params.locale);
|
|
34
37
|
|
|
35
38
|
const articles = computed<NsWowArticle[]>(
|
|
36
|
-
() =>
|
|
39
|
+
() => {
|
|
40
|
+
const lang = locale.value || config.value.locale;
|
|
41
|
+
return config.value?.articles[lang] ?? [];
|
|
42
|
+
},
|
|
37
43
|
);
|
|
38
44
|
|
|
39
45
|
export default function useArticles(): ComputedRef<NsWowArticle[]> {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import _instance from './instance';
|
|
1
2
|
import _useArticle from './article';
|
|
2
3
|
import _useArticles from './articles';
|
|
3
4
|
import _useConfig from './config';
|
|
@@ -10,6 +11,8 @@ import _useViewPort from './viewPort';
|
|
|
10
11
|
import _useLanguageSwitch from './languageSwitch';
|
|
11
12
|
import * as cssStyles from './cssStyles.ts'
|
|
12
13
|
|
|
14
|
+
export const setInstance = _instance.setInstance;
|
|
15
|
+
export const useInstance = _instance.useInstance;
|
|
13
16
|
export const useArticle = _useArticle;
|
|
14
17
|
export const useArticles = _useArticles;
|
|
15
18
|
export const useConfig = _useConfig;
|
|
@@ -24,6 +27,8 @@ export const addCssStyles = cssStyles.addCssStyles;
|
|
|
24
27
|
export const useCssStyles = cssStyles.useCssStyles;
|
|
25
28
|
|
|
26
29
|
export default {
|
|
30
|
+
setInstance,
|
|
31
|
+
useInstance,
|
|
27
32
|
useArticle,
|
|
28
33
|
useArticles,
|
|
29
34
|
useConfig,
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { setConfig } from '#composables/config';
|
|
2
|
+
import { setInstance } from '#composables/instance.ts'
|
|
2
3
|
import { createApp } from 'vue';
|
|
3
4
|
import { initI18n } from '@/i18n';
|
|
4
5
|
import srlVuePlugin from '#plugins/vueSrlPlugin';
|
|
5
6
|
import { clearPageState } from '#utils'
|
|
7
|
+
import Translate from '@/i18n/translation.ts'
|
|
6
8
|
|
|
7
9
|
import '#imports/app.scss';
|
|
8
10
|
|
|
@@ -10,15 +12,24 @@ import SrlPageApp from '../App.vue';
|
|
|
10
12
|
import router from '@/router';
|
|
11
13
|
|
|
12
14
|
export default async function initProject() {
|
|
15
|
+
const config = await setConfig();
|
|
13
16
|
router.beforeEach((to, from, next) => {
|
|
14
17
|
clearPageState();
|
|
15
18
|
next();
|
|
16
19
|
});
|
|
17
|
-
|
|
20
|
+
router.afterEach(() => {
|
|
21
|
+
if (
|
|
22
|
+
router.currentRoute.value.params.locale
|
|
23
|
+
&& config.value.locale !== router.currentRoute.value.params.locale
|
|
24
|
+
) {
|
|
25
|
+
Translate.switchLanguage(router.currentRoute.value.params.locale as string);
|
|
26
|
+
}
|
|
27
|
+
})
|
|
18
28
|
const i18n = initI18n();
|
|
19
29
|
const app = (window.app = createApp(SrlPageApp));
|
|
20
30
|
app.use(i18n);
|
|
21
31
|
app.use(router);
|
|
22
32
|
app.use(srlVuePlugin);
|
|
33
|
+
setInstance(app);
|
|
23
34
|
return app;
|
|
24
35
|
}
|
package/srl/.srl/utils/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { isRouterPath, isExternalPath } from './uri';
|
|
2
|
-
import { camelCase } from './
|
|
1
|
+
import { isFilePath, isRouterPath, isExternalPath } from './uri';
|
|
2
|
+
import { camelCase } from './string';
|
|
3
3
|
import { prepareHtmlContent } from './html';
|
|
4
4
|
import {
|
|
5
5
|
usePageState,
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
} from './pageState.ts';
|
|
16
16
|
|
|
17
17
|
export {
|
|
18
|
+
isFilePath,
|
|
18
19
|
isRouterPath,
|
|
19
20
|
isExternalPath,
|
|
20
21
|
camelCase,
|
package/srl/.srl/utils/uri.ts
CHANGED
|
@@ -1,36 +1,47 @@
|
|
|
1
|
+
export function isFilePath(path: string): boolean {
|
|
2
|
+
return (
|
|
3
|
+
path.endsWith('.pdf') ||
|
|
4
|
+
path.endsWith('.doc') ||
|
|
5
|
+
path.endsWith('.docx') ||
|
|
6
|
+
path.endsWith('.xls') ||
|
|
7
|
+
path.endsWith('.xlsx') ||
|
|
8
|
+
path.endsWith('.ppt') ||
|
|
9
|
+
path.endsWith('.pptx') ||
|
|
10
|
+
path.endsWith('.zip') ||
|
|
11
|
+
path.endsWith('.html') ||
|
|
12
|
+
path.endsWith('.htm') ||
|
|
13
|
+
path.endsWith('.php') ||
|
|
14
|
+
path.endsWith('.asp') ||
|
|
15
|
+
path.endsWith('.aspx') ||
|
|
16
|
+
path.endsWith('.jsp') ||
|
|
17
|
+
path.endsWith('.xml') ||
|
|
18
|
+
path.endsWith('.json') ||
|
|
19
|
+
path.endsWith('.txt') ||
|
|
20
|
+
path.endsWith('.svg') ||
|
|
21
|
+
path.endsWith('.png') ||
|
|
22
|
+
path.endsWith('.jpg') ||
|
|
23
|
+
path.endsWith('.jpeg') ||
|
|
24
|
+
path.endsWith('.gif') ||
|
|
25
|
+
path.endsWith('.webp')
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
1
29
|
export function isRouterPath(path: string): boolean {
|
|
2
30
|
return (
|
|
3
|
-
(
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
!path
|
|
11
|
-
!path.endsWith('.jsp') &&
|
|
12
|
-
!path.endsWith('.xml') &&
|
|
13
|
-
!path.endsWith('.json') &&
|
|
14
|
-
!path.endsWith('.txt') &&
|
|
15
|
-
!path.endsWith('.svg') &&
|
|
16
|
-
!path.endsWith('.png') &&
|
|
17
|
-
!path.endsWith('.jpg') &&
|
|
18
|
-
!path.endsWith('.jpeg') &&
|
|
19
|
-
!path.endsWith('.gif') &&
|
|
20
|
-
!path.endsWith('.webp') &&
|
|
21
|
-
!path.endsWith('.pdf') &&
|
|
22
|
-
!path.endsWith('.doc') &&
|
|
23
|
-
!path.endsWith('.docx') &&
|
|
24
|
-
!path.endsWith('.xls') &&
|
|
25
|
-
!path.endsWith('.xlsx') &&
|
|
26
|
-
!path.endsWith('.ppt') &&
|
|
27
|
-
!path.endsWith('.pptx') &&
|
|
28
|
-
!path.endsWith('.zip')
|
|
31
|
+
(
|
|
32
|
+
(
|
|
33
|
+
path.startsWith('/') &&
|
|
34
|
+
!path.startsWith('//')
|
|
35
|
+
) ||
|
|
36
|
+
path.startsWith('./')
|
|
37
|
+
) &&
|
|
38
|
+
!isFilePath(path)
|
|
29
39
|
);
|
|
30
40
|
}
|
|
31
41
|
|
|
32
42
|
export function isExternalPath(path: string): boolean {
|
|
33
43
|
return (
|
|
44
|
+
isFilePath(path) ||
|
|
34
45
|
path.startsWith('http') ||
|
|
35
46
|
path.startsWith('//') ||
|
|
36
47
|
path.startsWith('mailto') ||
|
|
@@ -49,6 +60,7 @@ export function isExternalPath(path: string): boolean {
|
|
|
49
60
|
}
|
|
50
61
|
|
|
51
62
|
export default {
|
|
63
|
+
isFilePath,
|
|
52
64
|
isRouterPath,
|
|
53
65
|
isExternalPath,
|
|
54
66
|
};
|
|
File without changes
|