@simple-reporting/base 1.0.33 → 1.0.35
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 +2 -1
- package/dev/src/assets/scss/app.scss +5 -0
- package/dev/src/assets/scss/pdf.scss +1 -1
- package/dev/vite.config.ts +4 -1
- package/devTools/SrlDevTools.vue +234 -0
- package/devTools/assets/Svg/Check.vue +7 -0
- package/devTools/assets/Svg/Close.vue +5 -0
- package/devTools/assets/Svg/Eye.vue +16 -0
- package/devTools/assets/Svg/Info.vue +7 -0
- package/devTools/assets/Svg/Settings.vue +5 -0
- package/devTools/assets/Svg/Uncheck.vue +7 -0
- package/devTools/box/Content.vue +93 -0
- package/devTools/components/BoxPanel.vue +23 -0
- package/devTools/components/Content.vue +17 -0
- package/devTools/config.ts +34 -0
- package/devTools/dialog/Colors.vue +33 -0
- package/devTools/dialog/Grid.vue +111 -0
- package/devTools/dialog/Settings.vue +62 -0
- package/devTools/dialog/Spacer.vue +110 -0
- package/devTools/dialog/ViewPort.vue +33 -0
- package/devTools/panel/Content.vue +50 -0
- package/devTools/settings.ts +28 -0
- package/devTools/utils/index.ts +7 -0
- package/devTools/utils/wheelResizeHandler.ts +19 -0
- package/livingdocs/010.Titles/020.title-h2/scss/general.scss +1 -16
- package/livingdocs/010.Titles/020.title-h2/scss/pdf.scss +16 -0
- package/livingdocs/010.Titles/020.title-h2/scss/web.scss +16 -0
- package/livingdocs/010.Titles/030.title-h3/scss/general.scss +0 -15
- package/livingdocs/010.Titles/030.title-h3/scss/pdf.scss +16 -0
- package/livingdocs/010.Titles/030.title-h3/scss/web.scss +16 -0
- package/livingdocs/010.Titles/040.title-h4/scss/general.scss +0 -15
- package/livingdocs/010.Titles/040.title-h4/scss/pdf.scss +16 -0
- package/livingdocs/010.Titles/040.title-h4/scss/web.scss +16 -0
- package/livingdocs/040.Media/010.table/scss/general.scss +6 -3
- package/livingdocs/110.PDF/100.pdf-toc-item/scss/general.scss +6 -1
- package/livingdocs/110.PDF/100.pdf-toc-item/scss/pdf.scss +6 -0
- package/package.json +8 -3
- package/plugins/viteSrlPlugin.js +19 -6
- package/scripts/build.d.ts +2 -0
- package/scripts/build.js +68 -3
- package/scripts/css/stripMediaFromCss.d.ts +17 -0
- package/scripts/css/stripMediaFromCss.js +147 -0
- package/scripts/vue/components.js +9 -2
- package/srl/.srl/App.vue +7 -1
- package/srl/.srl/components/Srl/Article/Accordion.vue +1 -0
- package/srl/.srl/components/Srl/Article/Root.vue +4 -4
- package/srl/.srl/components/Srl/Category/Accordion/Toggle.vue +2 -1
- package/srl/.srl/components/Srl/Menu/Item.vue +58 -24
- package/srl/.srl/components/Srl/Menu.vue +43 -17
- package/srl/.srl/composables/config.ts +4 -3
- package/srl/.srl/composables/index.ts +3 -0
- package/srl/.srl/composables/menu.ts +6 -3
- package/srl/.srl/composables/srlConfig.ts +3 -0
- package/srl/.srl/types/global.d.ts +11 -0
- package/srl/.srl/types/nswow.d.ts +5 -0
- package/srl/.srl/utils/html.ts +2 -2
- package/srl/.srl/utils/index.ts +27 -25
- package/srl/.srl/utils/object.ts +60 -0
package/scripts/build.js
CHANGED
|
@@ -20,12 +20,14 @@ import {
|
|
|
20
20
|
writeLivingDocsJson,
|
|
21
21
|
} from './utils.js';
|
|
22
22
|
import { nsWowInternalLddUrl } from './config.js';
|
|
23
|
-
import folders from './folders.js';
|
|
23
|
+
import folders, { srlSystem } from './folders.js';
|
|
24
24
|
import { mapLdd } from './ldd/mapLdd.js';
|
|
25
25
|
import { LivingdocsDesignValidator } from './ldd/LivingdocsDesignValidator.js';
|
|
26
26
|
import { camelCase } from './utils.js';
|
|
27
|
+
import { stripMediaFromCssFile } from './css/stripMediaFromCss.js';
|
|
27
28
|
import { buildVariables } from './build/variables.js';
|
|
28
29
|
import './dotenv.js';
|
|
30
|
+
import { readJson } from 'fs-extra/esm';
|
|
29
31
|
|
|
30
32
|
const placeholderId = '6297EAFB-33A0-48B8-8D64-E61CDC3E9035';
|
|
31
33
|
const nswowPath = folders.srlImports;
|
|
@@ -360,6 +362,11 @@ async function buildXbrl() {
|
|
|
360
362
|
}
|
|
361
363
|
}
|
|
362
364
|
|
|
365
|
+
async function finalizeXbrl() {
|
|
366
|
+
console.log('\n\nFinalize XBRL');
|
|
367
|
+
await stripMediaFromCssFile(join(folders.srlOutput, 'xbrl', 'xbrl.css'));
|
|
368
|
+
}
|
|
369
|
+
|
|
363
370
|
/**
|
|
364
371
|
* Builds Living Documentation (LDD) for a project.
|
|
365
372
|
*
|
|
@@ -370,7 +377,7 @@ async function buildXbrl() {
|
|
|
370
377
|
async function buildLdd(version) {
|
|
371
378
|
console.log('\n\nBuild Livingdocs');
|
|
372
379
|
buildVariables.system.environment = 'production';
|
|
373
|
-
buildVariables.system.build = '
|
|
380
|
+
buildVariables.system.build = 'editor';
|
|
374
381
|
buildVariables.system['size-unit'] = 'rem';
|
|
375
382
|
|
|
376
383
|
await checkFolders();
|
|
@@ -851,6 +858,10 @@ async function build(version, options = {}) {
|
|
|
851
858
|
await buildPdfCustomer(options.customer);
|
|
852
859
|
}
|
|
853
860
|
|
|
861
|
+
if (has('xbrl') || has('xhtml')) {
|
|
862
|
+
await finalizeXbrl();
|
|
863
|
+
}
|
|
864
|
+
|
|
854
865
|
if (has('ldd')) {
|
|
855
866
|
await zipLdd();
|
|
856
867
|
}
|
|
@@ -886,6 +897,60 @@ function cleanupScssAlias(string) {
|
|
|
886
897
|
return string.replace(/[^a-zA-Z0-9]/g, '');
|
|
887
898
|
}
|
|
888
899
|
|
|
900
|
+
async function generateUseSrlConfig() {
|
|
901
|
+
const content = await readJson(join(folders.root, 'srl.config.json'));
|
|
902
|
+
const c = [
|
|
903
|
+
`import { ref } from 'vue';`,
|
|
904
|
+
`const srlConfig = ref(${JSON.stringify(content, null, 2)})`,
|
|
905
|
+
'export default function useSrlConfig() {',
|
|
906
|
+
` return srlConfig`,
|
|
907
|
+
'}'
|
|
908
|
+
]
|
|
909
|
+
|
|
910
|
+
writeFileSync(
|
|
911
|
+
join(folders.srlComposables, 'srlConfig.ts'),
|
|
912
|
+
c.join('\n'),
|
|
913
|
+
);
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
async function mapIndexScss() {
|
|
917
|
+
const files = await glob(join(folders.srlAssets, 'scss', 'placeholders', '**', '*.scss'), {
|
|
918
|
+
withFileTypes: true,
|
|
919
|
+
nosort: false,
|
|
920
|
+
});
|
|
921
|
+
|
|
922
|
+
files.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
923
|
+
|
|
924
|
+
const relativePathToRoot = join('..', '/');
|
|
925
|
+
|
|
926
|
+
const map = [];
|
|
927
|
+
|
|
928
|
+
for (let x = 0; x < files.length; x++) {
|
|
929
|
+
const alias = cleanupScssAlias(files[x].relativePosix());
|
|
930
|
+
map.push(`@use "${relativePathToRoot}${files[x].relativePosix()}" as ${alias};`);
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
const c = [
|
|
934
|
+
`@use './config';`,
|
|
935
|
+
...map,
|
|
936
|
+
`@forward './system' as system-*;`,
|
|
937
|
+
`@forward './fonts' as fonts-*;`,
|
|
938
|
+
`@forward './grid' as grid-*;`,
|
|
939
|
+
`@forward './colors' as colors-*;`,
|
|
940
|
+
`@forward './typography' as typography-*;`,
|
|
941
|
+
`@forward './helpers' as helpers-*;`,
|
|
942
|
+
`@forward './spacer' as spacer-*;`,
|
|
943
|
+
`@forward './meta';`,
|
|
944
|
+
]
|
|
945
|
+
|
|
946
|
+
writeFileSync(
|
|
947
|
+
join(folders.srlSystem, 'index.scss'),
|
|
948
|
+
c.join('\n'),
|
|
949
|
+
);
|
|
950
|
+
|
|
951
|
+
return true;
|
|
952
|
+
}
|
|
953
|
+
|
|
889
954
|
/**
|
|
890
955
|
* Maps SCSS files and generates import statements for different output files.
|
|
891
956
|
*
|
|
@@ -1157,4 +1222,4 @@ async function map() {
|
|
|
1157
1222
|
return true;
|
|
1158
1223
|
}
|
|
1159
1224
|
|
|
1160
|
-
export { build, ddev, map, mapScss, mapLdd, mapJs };
|
|
1225
|
+
export { build, ddev, map, generateUseSrlConfig, mapIndexScss, mapScss, mapLdd, mapJs };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entfernt @media aus exakt einer CSS-Datei und ersetzt diese Datei durch das Ergebnis.
|
|
3
|
+
* @param {string} cssPath absoluter oder relativer Pfad zur .css Datei
|
|
4
|
+
*/
|
|
5
|
+
export function stripMediaFromCssFile(cssPath: string): Promise<{
|
|
6
|
+
file: string;
|
|
7
|
+
removed: number;
|
|
8
|
+
}>;
|
|
9
|
+
export type RemoveMediaPayload = {
|
|
10
|
+
params: string;
|
|
11
|
+
atRule: import("postcss").AtRule;
|
|
12
|
+
fullRuleText: string;
|
|
13
|
+
};
|
|
14
|
+
export type RemoveAllMediaPluginOptions = {
|
|
15
|
+
onRemoveMedia?: (payload: RemoveMediaPayload) => void;
|
|
16
|
+
shouldLogRemovedMedia?: (params: string, atRule: import("postcss").AtRule) => boolean;
|
|
17
|
+
};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { readFile, writeFile, stat } from 'node:fs/promises';
|
|
2
|
+
import postcss from 'postcss';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Entfernt alle @media-At-Rules aus CSS.
|
|
6
|
+
* Wichtig: bewusst AST-basiert (PostCSS), damit keine False-Positives entstehen.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const normalizeMediaParams = (params) =>
|
|
10
|
+
(params ?? '')
|
|
11
|
+
.trim()
|
|
12
|
+
// Whitespace normalisieren
|
|
13
|
+
.replace(/\s+/g, ' ')
|
|
14
|
+
// rund um Doppelpunkt vereinheitlichen
|
|
15
|
+
.replace(/\s*:\s*/g, ': ')
|
|
16
|
+
// "and" sauber trennen, falls Minifier Leerzeichen frisst
|
|
17
|
+
.replace(/\)\s*and\s*\(/gi, ') and (')
|
|
18
|
+
.replace(/\)and\(/gi, ') and (');
|
|
19
|
+
|
|
20
|
+
const isPrefersReducedMotionReduce = (params) => {
|
|
21
|
+
const p = normalizeMediaParams(params).toLowerCase();
|
|
22
|
+
return p === '(prefers-reduced-motion: reduce)';
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @typedef {{
|
|
27
|
+
* params: string,
|
|
28
|
+
* atRule: import('postcss').AtRule,
|
|
29
|
+
* fullRuleText: string
|
|
30
|
+
* }} RemoveMediaPayload
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @typedef {{
|
|
35
|
+
* onRemoveMedia?: (payload: RemoveMediaPayload) => void,
|
|
36
|
+
* shouldLogRemovedMedia?: (params: string, atRule: import('postcss').AtRule) => boolean
|
|
37
|
+
* }} RemoveAllMediaPluginOptions
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @param {RemoveAllMediaPluginOptions} [opts]
|
|
42
|
+
*/
|
|
43
|
+
const removeAllMediaPlugin = (opts = {}) => {
|
|
44
|
+
const {
|
|
45
|
+
onRemoveMedia = () => {},
|
|
46
|
+
shouldLogRemovedMedia = () => true,
|
|
47
|
+
} = opts;
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
postcssPlugin: 'remove-all-media',
|
|
51
|
+
AtRule: {
|
|
52
|
+
media: (atRule) => {
|
|
53
|
+
const params = atRule.params;
|
|
54
|
+
|
|
55
|
+
// erst loggen, dann entfernen
|
|
56
|
+
try {
|
|
57
|
+
if (shouldLogRemovedMedia(params, atRule)) {
|
|
58
|
+
// Wichtig: vor dem remove() stringifizieren, sonst ist der Knoten weg
|
|
59
|
+
const fullRuleText = atRule.toString();
|
|
60
|
+
onRemoveMedia({ params, atRule, fullRuleText });
|
|
61
|
+
}
|
|
62
|
+
} finally {
|
|
63
|
+
atRule.remove();
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
removeAllMediaPlugin.postcss = true;
|
|
70
|
+
|
|
71
|
+
async function fileExists(path) {
|
|
72
|
+
try {
|
|
73
|
+
const s = await stat(path);
|
|
74
|
+
return s.isFile();
|
|
75
|
+
} catch {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Entfernt @media aus exakt einer CSS-Datei und ersetzt diese Datei durch das Ergebnis.
|
|
82
|
+
* @param {string} cssPath absoluter oder relativer Pfad zur .css Datei
|
|
83
|
+
*/
|
|
84
|
+
export async function stripMediaFromCssFile(cssPath) {
|
|
85
|
+
const css = await readFile(cssPath, 'utf8');
|
|
86
|
+
const mapPath = `${cssPath}.map`;
|
|
87
|
+
const hasMap = await fileExists(mapPath);
|
|
88
|
+
|
|
89
|
+
const prevMap = hasMap ? JSON.parse(await readFile(mapPath, 'utf8')) : false;
|
|
90
|
+
|
|
91
|
+
/** @type {string[]} */
|
|
92
|
+
const removedEntries = [];
|
|
93
|
+
|
|
94
|
+
const result = await postcss([
|
|
95
|
+
removeAllMediaPlugin({
|
|
96
|
+
shouldLogRemovedMedia: (params) => !isPrefersReducedMotionReduce(params),
|
|
97
|
+
onRemoveMedia: ({ params, fullRuleText }) => {
|
|
98
|
+
const normalized = normalizeMediaParams(params);
|
|
99
|
+
// Eine Zeile pro Eintrag (inkl. Inhalt). Wir hängen den kompletten Block an,
|
|
100
|
+
// aber ohne das doppelte "@media ..." Prefix.
|
|
101
|
+
const body = fullRuleText.replace(/^@media\s+[^{}]+\s*/i, '');
|
|
102
|
+
removedEntries.push(`@media ${normalized} ${body}`);
|
|
103
|
+
},
|
|
104
|
+
}),
|
|
105
|
+
]).process(css, {
|
|
106
|
+
from: cssPath,
|
|
107
|
+
to: cssPath,
|
|
108
|
+
map: hasMap
|
|
109
|
+
? {
|
|
110
|
+
inline: false,
|
|
111
|
+
annotation: true,
|
|
112
|
+
prev: prevMap,
|
|
113
|
+
}
|
|
114
|
+
: false,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
await writeFile(cssPath, result.css ?? '', 'utf8');
|
|
118
|
+
|
|
119
|
+
if (hasMap && result.map) {
|
|
120
|
+
await writeFile(mapPath, result.map.toString(), 'utf8');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Output nur, wenn wirklich etwas entfernt wurde
|
|
124
|
+
if (removedEntries.length > 0) {
|
|
125
|
+
console.log('[strip-media]');
|
|
126
|
+
console.log('');
|
|
127
|
+
for (const line of removedEntries) console.log(line);
|
|
128
|
+
console.log('');
|
|
129
|
+
console.log(`[strip-media] result: removed ${removedEntries.length} @media block(s)`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return { file: cssPath, removed: removedEntries.length };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// CLI Nutzung: node scripts/stripMediaFromCss.mjs <cssFilePath>
|
|
136
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
137
|
+
const cssFilePath = process.argv[2];
|
|
138
|
+
if (!cssFilePath) {
|
|
139
|
+
console.error('Usage: node scripts/stripMediaFromCss.mjs <cssFilePath>');
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
stripMediaFromCssFile(cssFilePath).catch((e) => {
|
|
144
|
+
console.error(e);
|
|
145
|
+
process.exit(1);
|
|
146
|
+
});
|
|
147
|
+
}
|
|
@@ -39,8 +39,10 @@ export async function vueComponents() {
|
|
|
39
39
|
const appComponents = readVueDir(folders.srlSrc, '@/');
|
|
40
40
|
const srlComponents = readVueDir(folders.srlRoot, '#');
|
|
41
41
|
|
|
42
|
-
const components = [
|
|
43
|
-
|
|
42
|
+
const components = [
|
|
43
|
+
`app.component('SrlDevTools', defineAsyncComponent(() => import('@simple-reporting/base/devTools/SrlDevTools.vue')));`,
|
|
44
|
+
]
|
|
45
|
+
const types = [];
|
|
44
46
|
|
|
45
47
|
for (const [name, info] of Object.entries(appComponents)) {
|
|
46
48
|
components.push(
|
|
@@ -66,6 +68,11 @@ export async function vueComponents() {
|
|
|
66
68
|
}
|
|
67
69
|
}
|
|
68
70
|
|
|
71
|
+
types.push({
|
|
72
|
+
name: 'SrlDevTools',
|
|
73
|
+
type: ` type SrlDevTools = typeof import('@simple-reporting/base/devTools/SrlDevTools.vue')['default'];`,
|
|
74
|
+
});
|
|
75
|
+
|
|
69
76
|
writeFileSync(join(folders.srlPlugins, 'asyncSrlComponents.ts'),
|
|
70
77
|
`import { defineAsyncComponent, type App } from 'vue';
|
|
71
78
|
export default function asyncSrlComponents(app: App): void {
|
package/srl/.srl/App.vue
CHANGED
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
* to other components in the application.
|
|
37
37
|
*/
|
|
38
38
|
import App from '@/App.vue';
|
|
39
|
-
import { onMounted, watch } from 'vue'
|
|
39
|
+
import { computed, onMounted, watch } from 'vue'
|
|
40
40
|
import { useCssStyles } from '#composables'
|
|
41
41
|
import { setMounted } from '#utils'
|
|
42
42
|
|
|
@@ -51,6 +51,11 @@ watch(
|
|
|
51
51
|
},
|
|
52
52
|
{ immediate: true },
|
|
53
53
|
);
|
|
54
|
+
|
|
55
|
+
const devToolsEnabled = computed(() => {
|
|
56
|
+
return import.meta.env.DEV && import.meta.env.VITE_DISABLE_SRL_DEVTOOLS !== 'true'
|
|
57
|
+
})
|
|
58
|
+
|
|
54
59
|
onMounted(() => {
|
|
55
60
|
setMounted(true)
|
|
56
61
|
});
|
|
@@ -60,4 +65,5 @@ onMounted(() => {
|
|
|
60
65
|
<suspense>
|
|
61
66
|
<App />
|
|
62
67
|
</suspense>
|
|
68
|
+
<SrlDevTools v-if="devToolsEnabled" />
|
|
63
69
|
</template>
|
|
@@ -53,6 +53,7 @@ onMounted(() => {
|
|
|
53
53
|
content.value.id = id
|
|
54
54
|
content.value.setAttribute('tabindex', '-1')
|
|
55
55
|
toggle.value.setAttribute('aria-controls', id)
|
|
56
|
+
toggle.value.setAttribute('aria-expanded', 'false')
|
|
56
57
|
|
|
57
58
|
toggle.value.addEventListener('click', () => {
|
|
58
59
|
toggle.value?.getAttribute('aria-expanded') === 'true' ? close() : open()
|
|
@@ -44,13 +44,13 @@ const article = useArticle();
|
|
|
44
44
|
|
|
45
45
|
if (article.value) {
|
|
46
46
|
const file = `./html/${locale}/${article.value.name}.html`;
|
|
47
|
-
const publicationTitle = config.value.settings
|
|
48
|
-
|
|
47
|
+
const publicationTitle = config.value.settings?.publicationName?[locale] : null;
|
|
49
48
|
try {
|
|
50
49
|
const req = await fetch(file);
|
|
51
50
|
let text = await req.text();
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
const title = [article.value.translatedTitle];
|
|
52
|
+
publicationTitle ? title.push(publicationTitle as string) : null;
|
|
53
|
+
document.title = title.join(' - ');
|
|
54
54
|
content.value = prepareHtmlContent(text);
|
|
55
55
|
} catch (error) {
|
|
56
56
|
console.error(`Failed to load article content from ${file}:`, error);
|
|
@@ -49,17 +49,25 @@ const breadcrumb = defineModel<NsWowNavigationItem[]>('breadcrumb', {
|
|
|
49
49
|
required: true,
|
|
50
50
|
}) as Ref<NsWowNavigationItem[]>
|
|
51
51
|
|
|
52
|
-
const emit = defineEmits
|
|
53
|
-
'toggle',
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
'
|
|
62
|
-
|
|
52
|
+
const emit = defineEmits<{
|
|
53
|
+
(e: 'toggle', payload: {
|
|
54
|
+
element: HTMLAnchorElement | HTMLButtonElement
|
|
55
|
+
itemEl: HTMLLIElement
|
|
56
|
+
menu: SrlMenu
|
|
57
|
+
menuEl: HTMLUListElement
|
|
58
|
+
opened: boolean
|
|
59
|
+
props: typeof props
|
|
60
|
+
}): void
|
|
61
|
+
(e: 'open', payload: { index: number | string }): void
|
|
62
|
+
(e: 'close', payload: { index: number | string }): void
|
|
63
|
+
(e: 'link'): void
|
|
64
|
+
(e: 'routerChange'): void
|
|
65
|
+
(e: 'next', payload: { index: number | string }): void
|
|
66
|
+
(e: 'prev', payload: { index: number | string }): void
|
|
67
|
+
(e: 'tab'): void
|
|
68
|
+
(e: 'back'): void
|
|
69
|
+
}>()
|
|
70
|
+
|
|
63
71
|
const id = ref<number | string | undefined>()
|
|
64
72
|
if (props.item.children) {
|
|
65
73
|
id.value = useId()
|
|
@@ -68,7 +76,7 @@ if (props.item.children) {
|
|
|
68
76
|
const currentBackPath = computed<NsWowNavigationItem[]>(() => {
|
|
69
77
|
if (!props.item?.attributes?.class?.includes('srl-menu__link--back')) {
|
|
70
78
|
const i: NsWowNavigationItem = {
|
|
71
|
-
label: props.item.label
|
|
79
|
+
label: props.item.label,
|
|
72
80
|
}
|
|
73
81
|
props.item.title ? i.title = props.item.title : null
|
|
74
82
|
props.item.img ? i.img = props.item.img : null
|
|
@@ -87,13 +95,20 @@ const currentBackPath = computed<NsWowNavigationItem[]>(() => {
|
|
|
87
95
|
})
|
|
88
96
|
|
|
89
97
|
const currentPath = computed<NsWowNavigationItem[]>(() => {
|
|
90
|
-
return [...props.path,
|
|
98
|
+
return [...props.path, {
|
|
99
|
+
...props.item,
|
|
100
|
+
element: $el.value,
|
|
101
|
+
menu: menu.value,
|
|
102
|
+
menuEl: menu.value?.$el,
|
|
103
|
+
itemEl: li.value,
|
|
104
|
+
}]
|
|
91
105
|
})
|
|
92
106
|
|
|
93
107
|
const external = ref(props.item.href && isExternalPath(props.item.href))
|
|
94
108
|
|
|
95
|
-
const menu = ref()
|
|
96
|
-
const
|
|
109
|
+
const menu = ref<SrlMenu | null>(null)
|
|
110
|
+
const li = ref<HTMLLIElement>()
|
|
111
|
+
const $el = ref<HTMLAnchorElement | HTMLButtonElement>()
|
|
97
112
|
const opened = ref(false)
|
|
98
113
|
|
|
99
114
|
|
|
@@ -109,6 +124,7 @@ function toggleAction() {
|
|
|
109
124
|
} else {
|
|
110
125
|
menu.value.closeAll()
|
|
111
126
|
}
|
|
127
|
+
!props.item.callback || props.item.callback($el.value , li.value, menu.value.$el)
|
|
112
128
|
toggle()
|
|
113
129
|
}
|
|
114
130
|
function close() {
|
|
@@ -124,7 +140,18 @@ function closeSub() {
|
|
|
124
140
|
}
|
|
125
141
|
|
|
126
142
|
function toggle() {
|
|
127
|
-
emit('toggle'
|
|
143
|
+
emit('toggle', {
|
|
144
|
+
element: $el.value!,
|
|
145
|
+
itemEl: li.value!,
|
|
146
|
+
menu: menu.value,
|
|
147
|
+
menuEl: menu.value.$el,
|
|
148
|
+
opened: opened.value,
|
|
149
|
+
props: props,
|
|
150
|
+
})
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function toggleBridge(data) {
|
|
154
|
+
emit('toggle', data)
|
|
128
155
|
}
|
|
129
156
|
|
|
130
157
|
function next() {
|
|
@@ -154,7 +181,7 @@ function back(event: KeyboardEvent) {
|
|
|
154
181
|
}
|
|
155
182
|
|
|
156
183
|
function link() {
|
|
157
|
-
!props.item.callback || props.item.callback()
|
|
184
|
+
!props.item.callback || props.item.callback($el.value, li.value)
|
|
158
185
|
emit('link')
|
|
159
186
|
}
|
|
160
187
|
|
|
@@ -173,7 +200,13 @@ function closeItem() {
|
|
|
173
200
|
function findPath(): NsWowNavigationItem[] | null {
|
|
174
201
|
if (opened.value) {
|
|
175
202
|
if (props.item?.children?.length) {
|
|
176
|
-
let res = [...props.path,
|
|
203
|
+
let res = [...props.path, {
|
|
204
|
+
...props.item,
|
|
205
|
+
element: $el.value,
|
|
206
|
+
menu: menu.value,
|
|
207
|
+
menuEl: menu.value?.$el,
|
|
208
|
+
itemEl: li.value,
|
|
209
|
+
}]
|
|
177
210
|
menu.value.items.forEach((item) => {
|
|
178
211
|
item.opened && (res = item.findPath() || res)
|
|
179
212
|
})
|
|
@@ -194,12 +227,12 @@ defineExpose({
|
|
|
194
227
|
})
|
|
195
228
|
|
|
196
229
|
function internalLinkClick() {
|
|
197
|
-
!props.item.callback || props.item.callback()
|
|
230
|
+
!props.item.callback || props.item.callback($el.value , li.value)
|
|
198
231
|
routerChange()
|
|
199
232
|
}
|
|
200
233
|
|
|
201
234
|
function externalLinkClick() {
|
|
202
|
-
!props.item.callback || props.item.callback()
|
|
235
|
+
!props.item.callback || props.item.callback($el.value , li.value)
|
|
203
236
|
link()
|
|
204
237
|
}
|
|
205
238
|
|
|
@@ -237,7 +270,7 @@ const classListItem = computed(() => {
|
|
|
237
270
|
</script>
|
|
238
271
|
|
|
239
272
|
<template>
|
|
240
|
-
<li v-if="!item.children && props.item.href" role="none" :class="classListLi">
|
|
273
|
+
<li v-if="!item.children && props.item.href" ref="li" role="none" :class="classListLi">
|
|
241
274
|
<router-link
|
|
242
275
|
v-if="!external"
|
|
243
276
|
ref="$el"
|
|
@@ -289,7 +322,7 @@ const classListItem = computed(() => {
|
|
|
289
322
|
/>
|
|
290
323
|
</a>
|
|
291
324
|
</li>
|
|
292
|
-
<li v-else-if="props.item.callback" role="none" :class="classListLi">
|
|
325
|
+
<li v-else-if="!item.children && props.item.callback" ref="li" role="none" :class="classListLi">
|
|
293
326
|
<button
|
|
294
327
|
type="button"
|
|
295
328
|
ref="$el"
|
|
@@ -315,7 +348,7 @@ const classListItem = computed(() => {
|
|
|
315
348
|
/>
|
|
316
349
|
</button>
|
|
317
350
|
</li>
|
|
318
|
-
<li v-else :class="classListLi" role="none">
|
|
351
|
+
<li v-else :class="classListLi" ref="li" role="none">
|
|
319
352
|
<button
|
|
320
353
|
type="button"
|
|
321
354
|
ref="$el"
|
|
@@ -365,7 +398,8 @@ const classListItem = computed(() => {
|
|
|
365
398
|
@routerChange="emit('routerChange')"
|
|
366
399
|
@tab="tab"
|
|
367
400
|
@closeSub="closeSub"
|
|
368
|
-
@toggle="
|
|
401
|
+
@toggle="toggleBridge"
|
|
402
|
+
@backButtonClick="toggle"
|
|
369
403
|
/>
|
|
370
404
|
</li>
|
|
371
405
|
</template>
|
|
@@ -77,6 +77,30 @@ type BackButtonItem = {
|
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
type SrlMenuItemProps = {
|
|
81
|
+
name: string
|
|
82
|
+
item: NsWowNavigationItem
|
|
83
|
+
index: number | string
|
|
84
|
+
disableTab: boolean
|
|
85
|
+
disableTabIndex: boolean
|
|
86
|
+
initOpen: number
|
|
87
|
+
depth: number
|
|
88
|
+
disableClasses: boolean
|
|
89
|
+
backButtonEnabled: boolean
|
|
90
|
+
backButtonLabel: (backPath: NsWowNavigationItem[]) => string
|
|
91
|
+
backButtonItem?: BackButtonItem
|
|
92
|
+
backPath: NsWowNavigationItem[]
|
|
93
|
+
path: NsWowNavigationItem[]
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
type TogglePayload = {
|
|
97
|
+
element: HTMLAnchorElement | HTMLButtonElement
|
|
98
|
+
itemEl: HTMLLIElement
|
|
99
|
+
menu: SrlMenu
|
|
100
|
+
opened: boolean
|
|
101
|
+
props: SrlMenuItemProps
|
|
102
|
+
}
|
|
103
|
+
|
|
80
104
|
const props = withDefaults(
|
|
81
105
|
defineProps<{
|
|
82
106
|
name: string
|
|
@@ -108,17 +132,19 @@ const props = withDefaults(
|
|
|
108
132
|
},
|
|
109
133
|
)
|
|
110
134
|
|
|
111
|
-
const emit = defineEmits
|
|
112
|
-
'toggle',
|
|
113
|
-
'
|
|
114
|
-
'
|
|
115
|
-
'
|
|
116
|
-
'
|
|
117
|
-
'
|
|
118
|
-
'
|
|
119
|
-
'
|
|
120
|
-
'
|
|
121
|
-
|
|
135
|
+
const emit = defineEmits<{
|
|
136
|
+
(e: 'toggle', payload: TogglePayload): void
|
|
137
|
+
(e: 'backButtonClick'): void
|
|
138
|
+
(e: 'close'): void
|
|
139
|
+
(e: 'closeSub'): void
|
|
140
|
+
(e: 'link'): void
|
|
141
|
+
(e: 'routerChange'): void
|
|
142
|
+
(e: 'nextExceeded'): void
|
|
143
|
+
(e: 'prevExceeded'): void
|
|
144
|
+
(e: 'tab'): void
|
|
145
|
+
(e: 'back'): void
|
|
146
|
+
}>()
|
|
147
|
+
|
|
122
148
|
const items = ref<SrlMenuItem[]>([])
|
|
123
149
|
|
|
124
150
|
const opened = defineModel('opened', { type: Boolean, default: true })
|
|
@@ -140,7 +166,6 @@ function close() {
|
|
|
140
166
|
} else {
|
|
141
167
|
emit('close')
|
|
142
168
|
}
|
|
143
|
-
toggle()
|
|
144
169
|
}
|
|
145
170
|
|
|
146
171
|
function next(event: { index: number }) {
|
|
@@ -183,8 +208,8 @@ function routerChange() {
|
|
|
183
208
|
emit('routerChange')
|
|
184
209
|
}
|
|
185
210
|
|
|
186
|
-
function toggle() {
|
|
187
|
-
emit('toggle')
|
|
211
|
+
function toggle(data: TogglePayload) {
|
|
212
|
+
emit('toggle', data)
|
|
188
213
|
}
|
|
189
214
|
|
|
190
215
|
function closeAll(keep?: number | string) {
|
|
@@ -254,7 +279,10 @@ const menuItems = computed<NsWowNavigationItem[]>(() => {
|
|
|
254
279
|
'aria-controls': props.id ?? '',
|
|
255
280
|
'aria-expanded': String(opened.value)
|
|
256
281
|
}
|
|
257
|
-
backItem.callback =
|
|
282
|
+
backItem.callback = () => {
|
|
283
|
+
close()
|
|
284
|
+
emit('backButtonClick')
|
|
285
|
+
}
|
|
258
286
|
return [backItem, ...props.menu]
|
|
259
287
|
}
|
|
260
288
|
return props.menu
|
|
@@ -320,5 +348,3 @@ defineExpose({
|
|
|
320
348
|
</template>
|
|
321
349
|
</ul>
|
|
322
350
|
</template>
|
|
323
|
-
|
|
324
|
-
<style scoped lang="scss"></style>
|
|
@@ -39,11 +39,12 @@
|
|
|
39
39
|
* const config = useConfig()
|
|
40
40
|
*/
|
|
41
41
|
import { ref, type Ref } from 'vue';
|
|
42
|
+
import { objectDeepAssign } from '../utils/object.ts'
|
|
42
43
|
|
|
43
44
|
const config = ref<NsWowConfig>({
|
|
44
45
|
locale: 'de',
|
|
45
46
|
settings: {
|
|
46
|
-
languages: ['de'
|
|
47
|
+
languages: ['de'],
|
|
47
48
|
defaultLanguage: 'de',
|
|
48
49
|
shortBreadcrumb: false,
|
|
49
50
|
search: {
|
|
@@ -74,7 +75,7 @@ async function setConfig(): Promise<Ref<NsWowConfig>> {
|
|
|
74
75
|
|
|
75
76
|
const path = `/src/locales/${locale}.json`;
|
|
76
77
|
if (defaultMessages[path]) {
|
|
77
|
-
config.value.translations[locale] =
|
|
78
|
+
config.value.translations[locale] = objectDeepAssign(
|
|
78
79
|
defaultMessages[path],
|
|
79
80
|
config.value.translations[locale],
|
|
80
81
|
);
|
|
@@ -88,7 +89,7 @@ async function loadSettings() {
|
|
|
88
89
|
try {
|
|
89
90
|
const response: Response = await fetch(file);
|
|
90
91
|
const data: NsWowSettings = await response.json();
|
|
91
|
-
config.value.settings =
|
|
92
|
+
config.value.settings = objectDeepAssign(config.value.settings, data);
|
|
92
93
|
config.value.locale = data.defaultLanguage;
|
|
93
94
|
document.documentElement.lang = data.defaultLanguage;
|
|
94
95
|
} catch (e) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import _instance from './instance';
|
|
2
|
+
import _useSrlConfig from './srlConfig'
|
|
2
3
|
import _useArticle from './article';
|
|
3
4
|
import _useArticles from './articles';
|
|
4
5
|
import _useConfig from './config';
|
|
@@ -12,6 +13,7 @@ import _useLanguageSwitch from './languageSwitch';
|
|
|
12
13
|
import * as cssStyles from './cssStyles.ts'
|
|
13
14
|
|
|
14
15
|
export const setInstance = _instance.setInstance;
|
|
16
|
+
export const useSrlConfig = _useSrlConfig;
|
|
15
17
|
export const useInstance = _instance.useInstance;
|
|
16
18
|
export const useArticle = _useArticle;
|
|
17
19
|
export const useArticles = _useArticles;
|
|
@@ -29,6 +31,7 @@ export const useCssStyles = cssStyles.useCssStyles;
|
|
|
29
31
|
export default {
|
|
30
32
|
setInstance,
|
|
31
33
|
useInstance,
|
|
34
|
+
useSrlConfig,
|
|
32
35
|
useArticle,
|
|
33
36
|
useArticles,
|
|
34
37
|
useConfig,
|