@simple-reporting/base 1.0.14 → 1.0.15
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/040.Media/010.table/table/download.vue +494 -0
- package/livingdocs/040.Media/010.table/table/responsive.vue +104 -0
- package/livingdocs/040.Media/010.table/table.html +2 -2
- package/livingdocs/040.Media/010.table/table.vue +26 -0
- package/package.json +1 -1
- package/plugins/viteSrlPlugin.d.ts +2 -0
- package/plugins/viteSrlPlugin.js +18 -36
- package/scripts/vue/components.d.ts +1 -0
- package/scripts/vue/components.js +94 -0
- package/srl/components/Srl/Article/{DialogButton.vue → Dialog/Button.vue} +1 -1
- package/srl/components/Srl/Menu/Item/Content.vue +7 -14
- package/srl/components/Srl/Menu/Item.vue +5 -7
- package/srl/components/Srl/{Menu/List.vue → Menu.vue} +2 -3
- package/srl/components/Srl/Note/Accordion/Content.vue +1 -1
- package/srl/components/Srl/Page/Dialog.vue +1 -1
- package/srl/plugins/asyncLdComponent.ts +2 -2
- package/srl/plugins/asyncSrlComponents.ts +2 -0
- package/srl/plugins/initProject.ts +1 -1
- package/srl/plugins/vueSrlPlugin.ts +3 -20
- package/srl/types/components.d.ts +3 -17
- package/srl/types/global.d.ts +7 -0
- package/srl/types/nswow.d.ts +14 -14
- /package/srl/components/{Srl/Page/App.vue → App.vue} +0 -0
- /package/srl/components/Srl/Menu/Item/Content/{IconAfter.vue → Icon/After.vue} +0 -0
- /package/srl/components/Srl/Menu/Item/Content/{IconBefore.vue → Icon/Before.vue} +0 -0
- /package/srl/components/Srl/Menu/Item/Content/{ImageAfter.vue → Image/After.vue} +0 -0
- /package/srl/components/Srl/Menu/Item/Content/{ImageBefore.vue → Image/Before.vue} +0 -0
package/dev/package.json
CHANGED
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* This Vue component script enables downloading an HTML table as an Excel file.
|
|
4
|
+
* It uses the `exceljs` library to convert the table into an Excel format and trigger the download.
|
|
5
|
+
*
|
|
6
|
+
* ## Props:
|
|
7
|
+
* - `titleSelector` (string, optional): CSS selector for the table titles. Default: `.srl-title-h1__text, .srl-page-title__overline, .srl-page-title__headline`.
|
|
8
|
+
* - `font` (string, optional): Font used in the Excel file. Default: `Arial`.
|
|
9
|
+
* - `defaultSheetName` (string, optional): Default name of the Excel worksheet. Default: `Table 1`.
|
|
10
|
+
* - `defaultFileName` (string, optional): Default name of the downloaded file. Default: `Table`.
|
|
11
|
+
* - `spacerRowHeight` (number, optional): Height of spacer rows in the Excel file. Default: `25`.
|
|
12
|
+
* - `formatText` (Function, optional): Function to format cell content. Default: Trims text and returns `null` if empty.
|
|
13
|
+
*
|
|
14
|
+
* ## Types:
|
|
15
|
+
* - `FormatText`: Type for the `formatText` function.
|
|
16
|
+
* - `ElementStyles`: Style properties of an HTML element.
|
|
17
|
+
* - `TextData`: Text data with styles.
|
|
18
|
+
* - `CellData`: Data and styles of a table cell.
|
|
19
|
+
* - `CellStyles`: Styles of a table cell.
|
|
20
|
+
* - `TableIdElement`: HTML div element with a `data-tableid` attribute.
|
|
21
|
+
* - `TableMatrix`: Matrix representing the table structure.
|
|
22
|
+
*
|
|
23
|
+
* ## Functions:
|
|
24
|
+
* - `downloadTable()`: Initiates the download of the table as an Excel file.
|
|
25
|
+
* - `parseColumns(worksheet: Worksheet)`: Parses the column widths of the table and sets them in the worksheet.
|
|
26
|
+
* - `parseTitles()`: Extracts the table titles and their styles.
|
|
27
|
+
* - `writeTitles(worksheet: Worksheet, titles: TextData[])`: Writes the titles to the worksheet.
|
|
28
|
+
* - `parseTable()`: Converts the HTML table into a matrix of cells.
|
|
29
|
+
* - `writeTable(worksheet: Worksheet, matrix: TableMatrix)`: Writes the table matrix to the worksheet.
|
|
30
|
+
* - `mergeCells(worksheet: Worksheet, matrix: TableMatrix, excelRows: Row[])`: Merges cells with `rowSpan` or `colSpan`.
|
|
31
|
+
* - `parseFootNotes()`: Extracts footnotes from the table.
|
|
32
|
+
* - `writeFootNotes(worksheet: Worksheet, footNotes: TextData[])`: Writes the footnotes to the worksheet.
|
|
33
|
+
* - `triggerDownload(fileName: string, buffer: ArrayBuffer)`: Triggers the download of the Excel file.
|
|
34
|
+
* - `writeSpacerRow(worksheet: Worksheet)`: Adds a spacer row to the worksheet.
|
|
35
|
+
* - `parseElementStyles(element: HTMLElement)`: Parses the styles of an HTML element.
|
|
36
|
+
* - `rgbToArgb(rgb: string, alpha: number)`: Converts an RGB color to ARGB format.
|
|
37
|
+
* - `getStyles(tableCell: HTMLTableCellElement)`: Extracts the styles of a table cell.
|
|
38
|
+
*
|
|
39
|
+
* ## Usage:
|
|
40
|
+
* This component is used to export an HTML table to an Excel file.
|
|
41
|
+
* It can be integrated into a Vue application and provides a button to trigger the export.
|
|
42
|
+
*/
|
|
43
|
+
import { ref, watch } from 'vue'
|
|
44
|
+
import { Workbook } from 'exceljs'
|
|
45
|
+
import type { Worksheet, Row } from 'exceljs/index.d.ts'
|
|
46
|
+
|
|
47
|
+
const props = withDefaults(defineProps<{
|
|
48
|
+
component?: HTMLDivElement
|
|
49
|
+
tableSelector?: string
|
|
50
|
+
titleSelector?: string
|
|
51
|
+
buttonLabel?: string
|
|
52
|
+
buttonTitle?: string
|
|
53
|
+
buttonDescription?: string
|
|
54
|
+
font?: string
|
|
55
|
+
defaultSheetName?: string
|
|
56
|
+
defaultFileName?: string
|
|
57
|
+
spacerRowHeight?: number
|
|
58
|
+
formatText?: FormatText
|
|
59
|
+
}>(),{
|
|
60
|
+
tableSelector: 'table',
|
|
61
|
+
titleSelector: '.srl-title-h1__text, .srl-page-title__overline, .srl-page-title__headline',
|
|
62
|
+
buttonLabel: 'Download',
|
|
63
|
+
buttonDescription: 'Download table as Excel file',
|
|
64
|
+
font: 'Arial',
|
|
65
|
+
defaultSheetName: 'Table 1',
|
|
66
|
+
defaultFileName: 'Table',
|
|
67
|
+
spacerRowHeight: 25,
|
|
68
|
+
formatText: (cell: HTMLTableCellElement) => {
|
|
69
|
+
return cell.innerText !== '' ? cell.innerText.trim() : null
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
type FormatText = (cell: HTMLTableCellElement) => string | null
|
|
74
|
+
|
|
75
|
+
type ElementStyles = {
|
|
76
|
+
name: string,
|
|
77
|
+
size: number,
|
|
78
|
+
color: string,
|
|
79
|
+
bold: boolean
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
interface TextData extends ElementStyles {
|
|
83
|
+
value: string
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
type CellData = {
|
|
87
|
+
value: string | null,
|
|
88
|
+
styles: CellStyles,
|
|
89
|
+
colSpan: number,
|
|
90
|
+
rowSpan: number
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
type CellStyles = {
|
|
94
|
+
alignment: {
|
|
95
|
+
horizontal: string,
|
|
96
|
+
vertical: string,
|
|
97
|
+
wrapText: boolean
|
|
98
|
+
},
|
|
99
|
+
border: {
|
|
100
|
+
top?: { style: string, color: { argb: string } },
|
|
101
|
+
right?: { style: string, color: { argb: string } },
|
|
102
|
+
bottom?: { style: string, color: { argb: string } },
|
|
103
|
+
left?: { style: string, color: { argb: string } }
|
|
104
|
+
},
|
|
105
|
+
font: {
|
|
106
|
+
name: string,
|
|
107
|
+
size: number,
|
|
108
|
+
color: { argb: string },
|
|
109
|
+
bold: boolean
|
|
110
|
+
},
|
|
111
|
+
fill: {
|
|
112
|
+
type?: string,
|
|
113
|
+
pattern?: string,
|
|
114
|
+
fgColor?: { argb: string }
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
type TableIdElement = HTMLDivElement & {
|
|
119
|
+
dataset: {
|
|
120
|
+
tableid: string
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
type TableMatrix = Array<Array<CellData>>
|
|
125
|
+
|
|
126
|
+
const rootElement = ref<HTMLDivElement>()
|
|
127
|
+
const table = ref<HTMLTableElement | null | undefined>(null)
|
|
128
|
+
|
|
129
|
+
watch(
|
|
130
|
+
props,
|
|
131
|
+
to => {
|
|
132
|
+
!to.component || init(to.component)
|
|
133
|
+
}
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
function init(componentEl: HTMLDivElement | undefined) {
|
|
137
|
+
if (!componentEl) return
|
|
138
|
+
rootElement.value = componentEl
|
|
139
|
+
table.value = componentEl.querySelector(props.tableSelector) as HTMLTableElement
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function getTable(): Promise<HTMLTableElement | null | undefined> {
|
|
143
|
+
return new Promise((resolve, reject) => {
|
|
144
|
+
let attempts = 0;
|
|
145
|
+
const checkTable = () => {
|
|
146
|
+
const table = rootElement.value?.querySelector<HTMLTableElement>('table');
|
|
147
|
+
if (table) {
|
|
148
|
+
resolve(table);
|
|
149
|
+
} else if (attempts >= 30) {
|
|
150
|
+
reject(new Error('Table not found within the maximum number of attempts.'));
|
|
151
|
+
} else {
|
|
152
|
+
attempts++;
|
|
153
|
+
setTimeout(checkTable, 10);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
checkTable();
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async function downloadTable() {
|
|
162
|
+
if (!table.value) return
|
|
163
|
+
|
|
164
|
+
const matrix = parseTable()
|
|
165
|
+
const titles = parseTitles()
|
|
166
|
+
const footNotes = parseFootNotes()
|
|
167
|
+
const fileName = titles.map(t => t.value)
|
|
168
|
+
|
|
169
|
+
const headTop: HTMLTableCellElement | null | undefined = rootElement.value?.querySelector('.head_top')
|
|
170
|
+
if (headTop && headTop.textContent) {
|
|
171
|
+
fileName.push(headTop.textContent.trim())
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const tableIdElement = rootElement.value?.querySelector('[data-tableid]') as TableIdElement | null
|
|
175
|
+
|
|
176
|
+
const workbook = new Workbook()
|
|
177
|
+
const worksheet = workbook.addWorksheet( tableIdElement?.dataset.tableid || props.defaultSheetName )
|
|
178
|
+
|
|
179
|
+
parseColumns(worksheet)
|
|
180
|
+
|
|
181
|
+
writeTitles(worksheet, titles)
|
|
182
|
+
mergeCells(worksheet, matrix, writeTable(worksheet, matrix))
|
|
183
|
+
writeFootNotes(worksheet, footNotes)
|
|
184
|
+
|
|
185
|
+
triggerDownload(
|
|
186
|
+
fileName.length ? fileName.join(' - ').replaceAll(' ', '_') : props.defaultFileName,
|
|
187
|
+
await workbook.xlsx.writeBuffer()
|
|
188
|
+
)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function parseColumns(worksheet: Worksheet): void {
|
|
192
|
+
worksheet.columns = Array.from(table.value?.querySelectorAll('col') ?? [])
|
|
193
|
+
.map(col => {
|
|
194
|
+
return {
|
|
195
|
+
width: col.offsetWidth / 7
|
|
196
|
+
}
|
|
197
|
+
})
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function parseTitles(): TextData[] {
|
|
201
|
+
const titleElements: HTMLElement[] = Array.from(document.querySelectorAll(props.titleSelector)) as HTMLElement[]
|
|
202
|
+
const tableTitle: TextData[] = []
|
|
203
|
+
titleElements.forEach( element => {
|
|
204
|
+
if (!element || !element.textContent) return
|
|
205
|
+
const styles = parseElementStyles(element)
|
|
206
|
+
tableTitle.push(Object.assign({
|
|
207
|
+
value: element.textContent.trim(),
|
|
208
|
+
}, styles))
|
|
209
|
+
})
|
|
210
|
+
return tableTitle
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function writeTitles( worksheet: Worksheet, titles: TextData[] ): void {
|
|
214
|
+
if (titles.length === 0) return
|
|
215
|
+
|
|
216
|
+
titles.forEach( title => {
|
|
217
|
+
const row = worksheet.addRow([title.value])
|
|
218
|
+
const cell = row.getCell(1)
|
|
219
|
+
cell.font = {
|
|
220
|
+
name: title.name,
|
|
221
|
+
size: title.size,
|
|
222
|
+
color: { argb: title.color },
|
|
223
|
+
bold: title.bold
|
|
224
|
+
}
|
|
225
|
+
cell.alignment = {
|
|
226
|
+
wrapText: true
|
|
227
|
+
}
|
|
228
|
+
worksheet.mergeCells(row.number, 1, row.number, worksheet.columns.length)
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
//writeSpacerRow(worksheet)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function parseTable(): TableMatrix {
|
|
235
|
+
if (!table.value) return []
|
|
236
|
+
|
|
237
|
+
const matrix: TableMatrix = []
|
|
238
|
+
|
|
239
|
+
const tableRows = Array.from(table.value.querySelectorAll('tr'))
|
|
240
|
+
|
|
241
|
+
tableRows?.forEach( tableRowElem => {
|
|
242
|
+
const row: CellData[] = []
|
|
243
|
+
const tableCells: HTMLTableCellElement[] = Array.from(tableRowElem.querySelectorAll('th, td'))
|
|
244
|
+
|
|
245
|
+
tableCells.forEach( tableCellElem => {
|
|
246
|
+
|
|
247
|
+
const styles = getStyles(tableCellElem)
|
|
248
|
+
|
|
249
|
+
row.push({
|
|
250
|
+
value: props.formatText(tableCellElem),
|
|
251
|
+
styles: styles,
|
|
252
|
+
colSpan: tableCellElem.colSpan,
|
|
253
|
+
rowSpan: tableCellElem.rowSpan,
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
if (tableCellElem.colSpan > 1) {
|
|
257
|
+
for (let i = 1; i < tableCellElem.colSpan; i++) {
|
|
258
|
+
row.push({
|
|
259
|
+
value: null,
|
|
260
|
+
styles: styles,
|
|
261
|
+
colSpan: 1,
|
|
262
|
+
rowSpan: 1
|
|
263
|
+
})
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
})
|
|
267
|
+
|
|
268
|
+
matrix.push(row)
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
matrix.forEach( (row, rowIndex) => {
|
|
272
|
+
row.forEach( (cell) => {
|
|
273
|
+
const cellIndex = row.findIndex(c => c === cell)
|
|
274
|
+
if (cell.rowSpan > 1) {
|
|
275
|
+
for (let i = 1; i < cell.rowSpan; i++) {
|
|
276
|
+
const nextRow = matrix[rowIndex + i]
|
|
277
|
+
if (nextRow) {
|
|
278
|
+
for (let i = 0; i < cell.colSpan; i++) {
|
|
279
|
+
nextRow.splice(cellIndex, 0, {
|
|
280
|
+
value: null,
|
|
281
|
+
styles: cell.styles,
|
|
282
|
+
colSpan: 1,
|
|
283
|
+
rowSpan: 1
|
|
284
|
+
})
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
})
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
return matrix
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function writeTable( worksheet: Worksheet, matrix: TableMatrix ): Row[] {
|
|
296
|
+
const excelRows: Row[] = []
|
|
297
|
+
matrix.forEach( row => {
|
|
298
|
+
const excelRow = worksheet.addRow(row.map(cell => cell.value))
|
|
299
|
+
row.forEach( (cell, index) => {
|
|
300
|
+
const excelCell = excelRow.getCell(index + 1)
|
|
301
|
+
|
|
302
|
+
excelCell.alignment = cell.styles.alignment
|
|
303
|
+
excelCell.font = cell.styles.font
|
|
304
|
+
cell.styles.fill ? excelCell.fill = cell.styles.fill : null
|
|
305
|
+
excelCell.border = cell.styles.border
|
|
306
|
+
})
|
|
307
|
+
excelRows.push(excelRow)
|
|
308
|
+
})
|
|
309
|
+
return excelRows
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function mergeCells( worksheet: Worksheet, matrix: TableMatrix, excelRows: Row[] ): void {
|
|
313
|
+
matrix.forEach( (row, rowIndex) => {
|
|
314
|
+
row.forEach( (cell, cellIndex) => {
|
|
315
|
+
if (cell.rowSpan > 1 || cell.colSpan > 1) {
|
|
316
|
+
const excelRow = excelRows[rowIndex]
|
|
317
|
+
const startCell = cellIndex + 1
|
|
318
|
+
const endCell = cellIndex + cell.colSpan
|
|
319
|
+
const endRow = excelRow.number + ( cell.rowSpan - 1 )
|
|
320
|
+
worksheet.mergeCells(excelRow.number, startCell, endRow, endCell)
|
|
321
|
+
}
|
|
322
|
+
})
|
|
323
|
+
})
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function parseFootNotes(): TextData[] {
|
|
327
|
+
const footNoteData: TextData[] = []
|
|
328
|
+
const footNotes = Array.from(rootElement.value?.querySelectorAll('.srl-footnote') ?? []) as HTMLDivElement[]
|
|
329
|
+
|
|
330
|
+
footNotes.forEach(footNote => {
|
|
331
|
+
const key: HTMLSpanElement | null = footNote.querySelector('.srl-footnote__key')
|
|
332
|
+
const text: HTMLSpanElement | null = footNote.querySelector('.srl-footnote__text')
|
|
333
|
+
|
|
334
|
+
if (text && text.textContent) {
|
|
335
|
+
const row: string[] = []
|
|
336
|
+
if (key && key.textContent) {
|
|
337
|
+
row.push(key.textContent.trim())
|
|
338
|
+
}
|
|
339
|
+
row.push(text.textContent.trim())
|
|
340
|
+
const styles = parseElementStyles(text)
|
|
341
|
+
footNoteData.push(Object.assign({
|
|
342
|
+
value: row.join(' '),
|
|
343
|
+
}, styles))
|
|
344
|
+
}
|
|
345
|
+
})
|
|
346
|
+
return footNoteData
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
function writeFootNotes( worksheet: Worksheet, footNotes: TextData[] ): void {
|
|
350
|
+
if (footNotes.length === 0) return
|
|
351
|
+
|
|
352
|
+
writeSpacerRow(worksheet)
|
|
353
|
+
|
|
354
|
+
footNotes.forEach(footNote => {
|
|
355
|
+
const row = worksheet.addRow([footNote.value])
|
|
356
|
+
const cell = row.getCell(1)
|
|
357
|
+
cell.font = {
|
|
358
|
+
name: footNote.name,
|
|
359
|
+
size: footNote.size,
|
|
360
|
+
color: { argb: footNote.color },
|
|
361
|
+
bold: footNote.bold
|
|
362
|
+
}
|
|
363
|
+
cell.alignment = {
|
|
364
|
+
horizontal: 'left',
|
|
365
|
+
vertical: 'top',
|
|
366
|
+
wrapText: true
|
|
367
|
+
}
|
|
368
|
+
worksheet.mergeCells(row.number, 1, row.number, worksheet.columns.length)
|
|
369
|
+
})
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function triggerDownload( fileName: string, buffer: ArrayBuffer ): void {
|
|
373
|
+
const blob = new Blob([buffer], {
|
|
374
|
+
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
375
|
+
})
|
|
376
|
+
const link = document.createElement('a')
|
|
377
|
+
link.href = URL.createObjectURL(blob)
|
|
378
|
+
link.download = fileName + '.xlsx'
|
|
379
|
+
link.click()
|
|
380
|
+
link.remove()
|
|
381
|
+
URL.revokeObjectURL(link.href)
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
function writeSpacerRow(worksheet: Worksheet): void {
|
|
385
|
+
const row = worksheet.addRow([])
|
|
386
|
+
row.height = props.spacerRowHeight
|
|
387
|
+
worksheet.mergeCells(row.number, 1, row.number, worksheet.columns.length)
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function parseElementStyles(element: HTMLElement): ElementStyles | null {
|
|
391
|
+
const styles = window.getComputedStyle(element)
|
|
392
|
+
return {
|
|
393
|
+
name: props.font,
|
|
394
|
+
size: parseInt(styles.fontSize) * 0.75,
|
|
395
|
+
color: rgbToArgb(styles.color),
|
|
396
|
+
bold: parseInt(styles.fontWeight) > 400
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function rgbToArgb(rgb: string, alpha: number = 1): string {
|
|
401
|
+
const match = rgb.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([0-9.]+))?\)/)
|
|
402
|
+
if (!match) {
|
|
403
|
+
throw new Error("Dies ist keine gültige RGB- oder RGBA-Farbe")
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const r = parseInt(match[1])
|
|
407
|
+
const g = parseInt(match[2])
|
|
408
|
+
const b = parseInt(match[3])
|
|
409
|
+
const a = match[4] !== undefined ? Math.round(parseFloat(match[4]) * 255) : Math.round(alpha * 255)
|
|
410
|
+
|
|
411
|
+
const aHex = a.toString(16).padStart(2, '0')
|
|
412
|
+
const rHex = r.toString(16).padStart(2, '0')
|
|
413
|
+
const gHex = g.toString(16).padStart(2, '0')
|
|
414
|
+
const bHex = b.toString(16).padStart(2, '0')
|
|
415
|
+
|
|
416
|
+
return `${aHex}${rHex}${gHex}${bHex}`
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
function getStyles( tableCell: HTMLTableCellElement ): CellStyles {
|
|
420
|
+
const styles: CellStyles = {
|
|
421
|
+
alignment: {
|
|
422
|
+
horizontal: window.getComputedStyle(tableCell).textAlign,
|
|
423
|
+
vertical: window.getComputedStyle(tableCell).verticalAlign,
|
|
424
|
+
wrapText: true
|
|
425
|
+
},
|
|
426
|
+
border: {},
|
|
427
|
+
font: {
|
|
428
|
+
name: 'Arial',
|
|
429
|
+
size: parseInt(window.getComputedStyle(tableCell).fontSize) * 0.75,
|
|
430
|
+
color: { argb: rgbToArgb(window.getComputedStyle(tableCell).color) },
|
|
431
|
+
bold: parseInt(window.getComputedStyle(tableCell).fontWeight) > 400
|
|
432
|
+
},
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
const brdTopWidth = parseInt(window.getComputedStyle(tableCell).borderTopWidth)
|
|
436
|
+
if (brdTopWidth) {
|
|
437
|
+
styles.border.top = {
|
|
438
|
+
style: brdTopWidth < 3 ? 'thin' : brdTopWidth < 6 ? 'medium' : 'thick',
|
|
439
|
+
color: {argb: rgbToArgb(window.getComputedStyle(tableCell).borderTopColor)}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
const brdRightWidth = parseInt(window.getComputedStyle(tableCell).borderRightWidth)
|
|
444
|
+
if (brdRightWidth) {
|
|
445
|
+
styles.border.right = {
|
|
446
|
+
style: brdRightWidth < 3 ? 'thin' : brdRightWidth < 6 ? 'medium' : 'thick',
|
|
447
|
+
color: {argb: rgbToArgb(window.getComputedStyle(tableCell).borderRightColor)}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
const brdBottomWidth = parseInt(window.getComputedStyle(tableCell).borderBottomWidth)
|
|
452
|
+
if (brdBottomWidth) {
|
|
453
|
+
styles.border.bottom = {
|
|
454
|
+
style: brdBottomWidth < 3 ? 'thin' : brdBottomWidth < 6 ? 'medium' : 'thick',
|
|
455
|
+
color: {argb: rgbToArgb(window.getComputedStyle(tableCell).borderBottomColor)}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
const brdLeftWidth = parseInt(window.getComputedStyle(tableCell).borderLeftWidth)
|
|
460
|
+
if (brdLeftWidth) {
|
|
461
|
+
styles.border.left = {
|
|
462
|
+
style: brdLeftWidth < 3 ? 'thin' : brdLeftWidth < 6 ? 'medium' : 'thick',
|
|
463
|
+
color: {argb: rgbToArgb(window.getComputedStyle(tableCell).borderLeftColor)}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
const bgColor = rgbToArgb(window.getComputedStyle(tableCell).backgroundColor)
|
|
468
|
+
if (bgColor.substring(0,2) !== '00') {
|
|
469
|
+
styles.fill = {
|
|
470
|
+
type: 'pattern',
|
|
471
|
+
pattern: 'solid',
|
|
472
|
+
fgColor: {argb: bgColor}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
return styles
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
</script>
|
|
480
|
+
|
|
481
|
+
<template>
|
|
482
|
+
<button
|
|
483
|
+
v-if="table"
|
|
484
|
+
type="button"
|
|
485
|
+
:title="$te('table.download.title') ? $t('table.download.title') : props.buttonTitle ?? props.buttonLabel"
|
|
486
|
+
:aria-label="$te('table.download.label') ? $t('table.download.label') : props.buttonLabel"
|
|
487
|
+
:aria-description="$te('table.download.description') ? $t('table.download.description') : props.buttonDescription"
|
|
488
|
+
class="srl-button"
|
|
489
|
+
@click="downloadTable"
|
|
490
|
+
>
|
|
491
|
+
<i class="srl-icon srl-icon-download" aria-hidden="true"></i>
|
|
492
|
+
<span v-text="$te('table.download.label') ? $t('table.download.label') : props.buttonLabel" />
|
|
493
|
+
</button>
|
|
494
|
+
</template>
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, watch } from 'vue'
|
|
3
|
+
|
|
4
|
+
const props = withDefaults(defineProps<{
|
|
5
|
+
component?: HTMLDivElement
|
|
6
|
+
containerSelector?: string
|
|
7
|
+
tableSelector?: string
|
|
8
|
+
}>(), {
|
|
9
|
+
containerSelector: '.srl-table__container',
|
|
10
|
+
tableSelector: 'table'
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
const component = ref<HTMLDivElement>()
|
|
14
|
+
const table = ref<HTMLTableElement>()
|
|
15
|
+
const container = ref<HTMLDivElement>()
|
|
16
|
+
|
|
17
|
+
watch(
|
|
18
|
+
props,
|
|
19
|
+
to => {
|
|
20
|
+
!to.component || init(to.component)
|
|
21
|
+
}
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
function init(componentEl: HTMLDivElement | undefined) {
|
|
25
|
+
if (!componentEl) return
|
|
26
|
+
component.value = componentEl
|
|
27
|
+
table.value = componentEl.querySelector(props.tableSelector) as HTMLTableElement
|
|
28
|
+
container.value = componentEl.querySelector(props.containerSelector) as HTMLDivElement
|
|
29
|
+
updateClasses()
|
|
30
|
+
enableDragScroll()
|
|
31
|
+
window.addEventListener('resize', updateClasses)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
defineExpose({
|
|
35
|
+
init
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
function hasHorizontalScrollbar(): boolean {
|
|
39
|
+
return !table.value || !container.value ?
|
|
40
|
+
false :
|
|
41
|
+
table.value?.clientWidth > container.value?.clientWidth
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function hasRowSpan() {
|
|
45
|
+
if (!table.value) return false
|
|
46
|
+
const tableCells = table.value.querySelectorAll('td[rowspan]')
|
|
47
|
+
return tableCells.length > 0
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function updateClasses() {
|
|
51
|
+
const hasScroll = hasHorizontalScrollbar()
|
|
52
|
+
const hasRowspan = hasRowSpan()
|
|
53
|
+
|
|
54
|
+
if (hasScroll && !hasRowspan) {
|
|
55
|
+
component.value?.classList.add('has-shadow', 'responsive-table')
|
|
56
|
+
component.value?.classList.remove('responsive-table-alternative')
|
|
57
|
+
} else if (hasScroll && hasRowspan) {
|
|
58
|
+
component.value?.classList.add('responsive-table-alternative')
|
|
59
|
+
component.value?.classList.remove('has-shadow', 'responsive-table')
|
|
60
|
+
} else {
|
|
61
|
+
component.value?.classList.remove('has-shadow', 'responsive-table', 'responsive-table-alternative')
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function enableDragScroll() {
|
|
66
|
+
let isDragging: boolean = false;
|
|
67
|
+
let startX: number = 0;
|
|
68
|
+
let scrollLeft: number = 0;
|
|
69
|
+
|
|
70
|
+
if (container.value) {
|
|
71
|
+
container.value.addEventListener('mousedown', (e) => {
|
|
72
|
+
if (container.value) {
|
|
73
|
+
isDragging = true;
|
|
74
|
+
startX = e.pageX - container.value.offsetLeft;
|
|
75
|
+
scrollLeft = container.value.scrollLeft;
|
|
76
|
+
container.value.classList.add('dragging');
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
container.value.addEventListener('mousemove', (e) => {
|
|
81
|
+
if (container.value) {
|
|
82
|
+
if (!isDragging) return;
|
|
83
|
+
e.preventDefault();
|
|
84
|
+
const x = e.pageX - container.value.offsetLeft;
|
|
85
|
+
const walk = (x - startX) * 2; // Adjust speed
|
|
86
|
+
container.value.scrollLeft = scrollLeft - walk;
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
container.value.addEventListener('mouseup', () => {
|
|
91
|
+
isDragging = false;
|
|
92
|
+
container.value?.classList.remove('dragging');
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
container.value.addEventListener('mouseleave', () => {
|
|
96
|
+
isDragging = false;
|
|
97
|
+
container.value?.classList.remove('dragging');
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
</script>
|
|
102
|
+
|
|
103
|
+
<template>
|
|
104
|
+
</template>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<
|
|
1
|
+
<srl-ld-table class="srl-table">
|
|
2
2
|
<div class="srl-table__container" doc-include="nswow-table">
|
|
3
3
|
<p class="srl-grid srl-paragraph">
|
|
4
4
|
<span class="srl-grid__inner srl-paragraph__text">
|
|
@@ -6,4 +6,4 @@
|
|
|
6
6
|
</span>
|
|
7
7
|
</p>
|
|
8
8
|
</div>
|
|
9
|
-
</
|
|
9
|
+
</srl-ld-table>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
|
|
3
|
+
const props = withDefaults(defineProps<{
|
|
4
|
+
responsive?: boolean
|
|
5
|
+
download?: boolean
|
|
6
|
+
}>(), {
|
|
7
|
+
responsive: false,
|
|
8
|
+
download: false,
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
import { ref } from 'vue'
|
|
12
|
+
import TableResponsive from './table/responsive.vue'
|
|
13
|
+
import TableDownload from './table/download.vue'
|
|
14
|
+
|
|
15
|
+
const component = ref<HTMLDivElement>()
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<div ref="component">
|
|
20
|
+
<TableResponsive v-if="props.responsive" :component="component" />
|
|
21
|
+
<slot/>
|
|
22
|
+
<div v-if="props.download" class="srl-table__download">
|
|
23
|
+
<TableDownload :component="component" />
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
</template>
|
package/package.json
CHANGED
package/plugins/viteSrlPlugin.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { existsSync, readFileSync, writeFileSync, readdirSync, statSync } from 'node:fs';
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
3
2
|
import { join, relative } from 'node:path/posix';
|
|
4
3
|
import { execSync } from 'node:child_process';
|
|
5
4
|
import folders from '../scripts/folders.js';
|
|
@@ -14,6 +13,7 @@ import {
|
|
|
14
13
|
mapScss,
|
|
15
14
|
} from '../scripts/build.js';
|
|
16
15
|
import chalk from 'chalk';
|
|
16
|
+
import { vueComponents } from '../scripts/vue/components.js';
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
/**
|
|
@@ -36,10 +36,8 @@ function printPromptsMessage(messages) {
|
|
|
36
36
|
console.log('');
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
|
|
40
39
|
const data = {
|
|
41
|
-
version: null
|
|
42
|
-
components:{}
|
|
40
|
+
version: null
|
|
43
41
|
};
|
|
44
42
|
const srlConfig = readConfigJson();
|
|
45
43
|
|
|
@@ -95,39 +93,9 @@ function checkForUpdates() {
|
|
|
95
93
|
}
|
|
96
94
|
} catch (e) {}
|
|
97
95
|
}
|
|
98
|
-
|
|
99
|
-
function findVueFilesInSrl() {
|
|
100
|
-
const componentsPath = join(folders.srlSrc, 'components');
|
|
101
|
-
const baseDir = join(componentsPath, 'Srl');
|
|
102
|
-
const result = {};
|
|
103
|
-
|
|
104
|
-
function search(dir) {
|
|
105
|
-
for (const entry of readdirSync(dir)) {
|
|
106
|
-
const fullPath = join(dir, entry);
|
|
107
|
-
if (statSync(fullPath).isDirectory()) {
|
|
108
|
-
search(fullPath);
|
|
109
|
-
} else if (entry.endsWith('.vue')) {
|
|
110
|
-
const path = relative(componentsPath, fullPath);
|
|
111
|
-
const name = path.slice(0, -4)
|
|
112
|
-
.replaceAll('/', '')
|
|
113
|
-
.replaceAll('\\', '');
|
|
114
|
-
|
|
115
|
-
result[name] = `@/components/${path}`;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
if (existsSync(baseDir) && statSync(baseDir).isDirectory()) {
|
|
121
|
-
search(baseDir);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
return result;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
96
|
async function startActions() {
|
|
128
97
|
data.version = getPackageVersion();
|
|
129
98
|
checkForUpdates();
|
|
130
|
-
data.components = findVueFilesInSrl();
|
|
131
99
|
if (!srlConfig || JSON.stringify(srlConfig) !== JSON.stringify(data)) {
|
|
132
100
|
writeConfigJson(data);
|
|
133
101
|
}
|
|
@@ -139,6 +107,7 @@ async function startActions() {
|
|
|
139
107
|
]);
|
|
140
108
|
}
|
|
141
109
|
|
|
110
|
+
await vueComponents();
|
|
142
111
|
await beaver(0);
|
|
143
112
|
await map();
|
|
144
113
|
await mapJs();
|
|
@@ -160,7 +129,6 @@ export default function viteSrlPlugin() {
|
|
|
160
129
|
return {
|
|
161
130
|
name: 'vite-srl-plugin',
|
|
162
131
|
config(config) {
|
|
163
|
-
|
|
164
132
|
startActions();
|
|
165
133
|
|
|
166
134
|
config.base = './';
|
|
@@ -229,6 +197,13 @@ export default function viteSrlPlugin() {
|
|
|
229
197
|
) {
|
|
230
198
|
triggerAction(mapLdd);
|
|
231
199
|
}
|
|
200
|
+
|
|
201
|
+
if (
|
|
202
|
+
path.includes('src/components/Srl') &&
|
|
203
|
+
path.endsWith('.vue')
|
|
204
|
+
) {
|
|
205
|
+
triggerAction(vueComponents);
|
|
206
|
+
}
|
|
232
207
|
});
|
|
233
208
|
|
|
234
209
|
server.watcher.on('unlink', (path) => {
|
|
@@ -264,6 +239,13 @@ export default function viteSrlPlugin() {
|
|
|
264
239
|
) {
|
|
265
240
|
triggerAction(mapLdd);
|
|
266
241
|
}
|
|
242
|
+
|
|
243
|
+
if (
|
|
244
|
+
path.includes('src/components/Srl') &&
|
|
245
|
+
path.endsWith('.vue')
|
|
246
|
+
) {
|
|
247
|
+
triggerAction(vueComponents);
|
|
248
|
+
}
|
|
267
249
|
});
|
|
268
250
|
},
|
|
269
251
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function vueComponents(): Promise<void>;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import folders from '../folders.js';
|
|
2
|
+
import { join, relative } from 'node:path/posix';
|
|
3
|
+
import { existsSync, readdirSync, statSync, writeFileSync } from 'node:fs';
|
|
4
|
+
|
|
5
|
+
function toPascalAfterSlash(str) {
|
|
6
|
+
return str.replace(/\/(.)/g, (_, c) => c.toUpperCase());
|
|
7
|
+
}
|
|
8
|
+
function readVueDir(entryPath, prefix = '') {
|
|
9
|
+
const componentsPath = join(entryPath, 'components');
|
|
10
|
+
const baseDir = join(componentsPath, 'Srl');
|
|
11
|
+
const result = {};
|
|
12
|
+
|
|
13
|
+
function search(dir) {
|
|
14
|
+
for (const entry of readdirSync(dir)) {
|
|
15
|
+
const fullPath = join(dir, entry);
|
|
16
|
+
if (statSync(fullPath).isDirectory()) {
|
|
17
|
+
search(fullPath);
|
|
18
|
+
} else if (entry.endsWith('.vue')) {
|
|
19
|
+
const path = relative(componentsPath, fullPath);
|
|
20
|
+
let name = path.slice(0, -4);
|
|
21
|
+
name = toPascalAfterSlash(name);
|
|
22
|
+
name = name.replaceAll('/', '');
|
|
23
|
+
|
|
24
|
+
result[name] = {
|
|
25
|
+
component: `${prefix}components/${path}`,
|
|
26
|
+
type: relative(folders.srlTypes, fullPath)
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (existsSync(baseDir) && statSync(baseDir).isDirectory()) {
|
|
33
|
+
search(baseDir);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export async function vueComponents() {
|
|
40
|
+
const srlComponents = readVueDir(folders.srlRoot, '#');
|
|
41
|
+
const appComponents = readVueDir(folders.srlSrc, '@/');
|
|
42
|
+
|
|
43
|
+
const components = []
|
|
44
|
+
const types = []
|
|
45
|
+
|
|
46
|
+
for (const [name, info] of Object.entries(srlComponents)) {
|
|
47
|
+
const componentPath = appComponents[name] ? appComponents[name].component : info.component
|
|
48
|
+
const typePath = appComponents[name] ? appComponents[name].type : info.type
|
|
49
|
+
components.push(
|
|
50
|
+
`app.component('${name}', defineAsyncComponent(() => import('${componentPath}')));`,
|
|
51
|
+
)
|
|
52
|
+
types.push({
|
|
53
|
+
name: name,
|
|
54
|
+
type: ` type ${name} = typeof import('${typePath}')['default'];`,
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
for (const [name, info] of Object.entries(appComponents)) {
|
|
59
|
+
if (!srlComponents[name]) {
|
|
60
|
+
components.push(
|
|
61
|
+
`app.component('${name}', defineAsyncComponent(() => import('${info.component}')));`,
|
|
62
|
+
)
|
|
63
|
+
types.push({
|
|
64
|
+
name: name,
|
|
65
|
+
type: ` type ${name} = typeof import('${info.type}')['default'];`,
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
writeFileSync(join(folders.srlPlugins, 'asyncSrlComponents.ts'),
|
|
71
|
+
`import { defineAsyncComponent } from 'vue';
|
|
72
|
+
export default function asyncSrlComponents(app) {
|
|
73
|
+
${components.join('\n ')}
|
|
74
|
+
}
|
|
75
|
+
`, 'utf8');
|
|
76
|
+
|
|
77
|
+
const componentsInterface = types.map(t => {
|
|
78
|
+
return ` ${t.name}: ${t.name};`
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
writeFileSync(join(folders.srlTypes, 'components.d.ts'),
|
|
82
|
+
`export {};
|
|
83
|
+
declare global {
|
|
84
|
+
${types.map(t=>t.type).join("\n")}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
interface _GlobalComponents {
|
|
88
|
+
${componentsInterface.join("\n")}
|
|
89
|
+
}
|
|
90
|
+
declare module '@vue/runtime-core' {
|
|
91
|
+
export interface GlobalComponents extends _GlobalComponents {}
|
|
92
|
+
}
|
|
93
|
+
`, 'utf8');
|
|
94
|
+
}
|
|
@@ -11,7 +11,7 @@ const config = useConfig();
|
|
|
11
11
|
const articles = useArticles();
|
|
12
12
|
const id = ref<string>(`srl-page__dialog-${useId()}`);
|
|
13
13
|
const content = ref<string>('');
|
|
14
|
-
const dialog = ref<
|
|
14
|
+
const dialog = ref<SrlPageDialog | null>(null);
|
|
15
15
|
async function loadContent() {
|
|
16
16
|
const article = articles.value.find((article) => article.uuid === props.uuid);
|
|
17
17
|
if (article) {
|
|
@@ -1,11 +1,4 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import MenuItemContentText from './Content/Text.vue';
|
|
3
|
-
import MenuItemContentImage from './Content/Image.vue';
|
|
4
|
-
import MenuItemContentImageBefore from './Content/ImageBefore.vue';
|
|
5
|
-
import MenuItemContentImageAfter from './Content/ImageAfter.vue';
|
|
6
|
-
import MenuItemContentIcon from './Content/Icon.vue';
|
|
7
|
-
import MenuItemContentIconBefore from './Content/IconBefore.vue';
|
|
8
|
-
import MenuItemContentIconAfter from './Content/IconAfter.vue';
|
|
9
2
|
|
|
10
3
|
const props = defineProps<{
|
|
11
4
|
item: NsWowNavigationItem
|
|
@@ -15,43 +8,43 @@ const props = defineProps<{
|
|
|
15
8
|
</script>
|
|
16
9
|
|
|
17
10
|
<template>
|
|
18
|
-
<
|
|
11
|
+
<SrlMenuItemContentIcon
|
|
19
12
|
v-if="props.item.icon"
|
|
20
13
|
:item="props.item"
|
|
21
14
|
:depth="props.depth"
|
|
22
15
|
:disableClasses="props.disableClasses"
|
|
23
16
|
/>
|
|
24
|
-
<
|
|
17
|
+
<SrlMenuItemContentIconBefore
|
|
25
18
|
v-else-if="props.item.iconBefore"
|
|
26
19
|
:item="props.item"
|
|
27
20
|
:depth="props.depth"
|
|
28
21
|
:disableClasses="props.disableClasses"
|
|
29
22
|
/>
|
|
30
|
-
<
|
|
23
|
+
<SrlMenuItemContentIconAfter
|
|
31
24
|
v-else-if="props.item.iconAfter"
|
|
32
25
|
:item="props.item"
|
|
33
26
|
:depth="props.depth"
|
|
34
27
|
:disableClasses="props.disableClasses"
|
|
35
28
|
/>
|
|
36
|
-
<
|
|
29
|
+
<SrlMenuItemContentImage
|
|
37
30
|
v-else-if="props.item.img"
|
|
38
31
|
:item="props.item"
|
|
39
32
|
:depth="props.depth"
|
|
40
33
|
:disableClasses="props.disableClasses"
|
|
41
34
|
/>
|
|
42
|
-
<
|
|
35
|
+
<SrlMenuItemContentImageBefore
|
|
43
36
|
v-else-if="props.item.imgBefore"
|
|
44
37
|
:item="props.item"
|
|
45
38
|
:depth="props.depth"
|
|
46
39
|
:disableClasses="props.disableClasses"
|
|
47
40
|
/>
|
|
48
|
-
<
|
|
41
|
+
<SrlMenuItemContentImageAfter
|
|
49
42
|
v-else-if="props.item.imgAfter"
|
|
50
43
|
:item="props.item"
|
|
51
44
|
:depth="props.depth"
|
|
52
45
|
:disableClasses="props.disableClasses"
|
|
53
46
|
/>
|
|
54
|
-
<
|
|
47
|
+
<SrlMenuItemContentText
|
|
55
48
|
v-else
|
|
56
49
|
:item="props.item"
|
|
57
50
|
:depth="props.depth"
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed, nextTick, ref, useId } from 'vue'
|
|
3
|
-
import MenuItemContent from './Item/Content.vue'
|
|
4
|
-
import MenuList from './List.vue'
|
|
5
3
|
import type { RouterLink } from 'vue-router'
|
|
6
4
|
import { isExternalPath } from '#utils/uri'
|
|
7
5
|
|
|
@@ -187,7 +185,7 @@ const classListItem = computed(() => {
|
|
|
187
185
|
@keydown.shift.tab.exact="back"
|
|
188
186
|
@keydown.esc.stop.prevent="close"
|
|
189
187
|
>
|
|
190
|
-
<
|
|
188
|
+
<SrlMenuItemContent
|
|
191
189
|
:item="props.item"
|
|
192
190
|
:depth="props.depth"
|
|
193
191
|
:disableClasses="props.disableClasses"
|
|
@@ -212,7 +210,7 @@ const classListItem = computed(() => {
|
|
|
212
210
|
@keydown.shift.tab.exact="back"
|
|
213
211
|
@keydown.esc.stop.prevent="close"
|
|
214
212
|
>
|
|
215
|
-
<
|
|
213
|
+
<SrlMenuItemContent
|
|
216
214
|
:item="props.item"
|
|
217
215
|
:depth="props.depth"
|
|
218
216
|
:disableClasses="props.disableClasses"
|
|
@@ -237,7 +235,7 @@ const classListItem = computed(() => {
|
|
|
237
235
|
@keydown.shift.tab.exact="back"
|
|
238
236
|
@keydown.esc.stop.prevent="close"
|
|
239
237
|
>
|
|
240
|
-
<
|
|
238
|
+
<SrlMenuItemContent
|
|
241
239
|
:item="props.item"
|
|
242
240
|
:depth="props.depth"
|
|
243
241
|
:disableClasses="props.disableClasses"
|
|
@@ -265,13 +263,13 @@ const classListItem = computed(() => {
|
|
|
265
263
|
@keydown.shift.tab.exact="back"
|
|
266
264
|
@keydown.esc.stop.prevent="close"
|
|
267
265
|
>
|
|
268
|
-
<
|
|
266
|
+
<SrlMenuItemContent
|
|
269
267
|
:item="props.item"
|
|
270
268
|
:depth="props.depth"
|
|
271
269
|
:disableClasses="props.disableClasses"
|
|
272
270
|
/>
|
|
273
271
|
</button>
|
|
274
|
-
<
|
|
272
|
+
<SrlMenu
|
|
275
273
|
v-if="props.item.children"
|
|
276
274
|
ref="menu"
|
|
277
275
|
:id="`${props.name}-${id}`"
|
|
@@ -51,7 +51,6 @@
|
|
|
51
51
|
* />
|
|
52
52
|
*/
|
|
53
53
|
import { computed, ref } from 'vue'
|
|
54
|
-
import MenuItem from './Item.vue'
|
|
55
54
|
|
|
56
55
|
type BackButtonItem = {
|
|
57
56
|
title?: string
|
|
@@ -108,7 +107,7 @@ const emit = defineEmits([
|
|
|
108
107
|
'tab',
|
|
109
108
|
'back',
|
|
110
109
|
])
|
|
111
|
-
const items = ref<
|
|
110
|
+
const items = ref<SrlMenuItem[]>([])
|
|
112
111
|
|
|
113
112
|
const opened = defineModel('opened', { type: Boolean, default: true })
|
|
114
113
|
|
|
@@ -247,7 +246,7 @@ defineExpose({
|
|
|
247
246
|
@keydown.left.prevent.stop="focusClickable(menuItems.length - 1)"
|
|
248
247
|
>
|
|
249
248
|
<template v-for="(item, index) in menuItems" :key="index">
|
|
250
|
-
<
|
|
249
|
+
<SrlMenuItem
|
|
251
250
|
ref="items"
|
|
252
251
|
:item="item"
|
|
253
252
|
:name="props.name"
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { defineAsyncComponent } from 'vue'
|
|
2
|
-
export default function asyncLdComponent(app) {}
|
|
1
|
+
import { defineAsyncComponent } from 'vue'
|
|
2
|
+
export default function asyncLdComponent(app) {}
|
|
@@ -5,7 +5,7 @@ import srlVuePlugin from '#plugins/vueSrlPlugin';
|
|
|
5
5
|
|
|
6
6
|
import '#imports/app.scss';
|
|
7
7
|
|
|
8
|
-
import SrlPageApp from '#components/
|
|
8
|
+
import SrlPageApp from '#components/App.vue';
|
|
9
9
|
import router from '@/router';
|
|
10
10
|
|
|
11
11
|
export default async function initProject() {
|
|
@@ -1,27 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import SrlAriaTabChain from '#components/Srl/Aria/TabChain.vue';
|
|
3
|
-
import SrlArticleAutoload from '#components/Srl/Article/Autoload.vue';
|
|
4
|
-
import SrlArticleRoot from '#components/Srl/Article/Root.vue';
|
|
5
|
-
import SrlArticleDialogButton from '#components/Srl/Article/DialogButton.vue';
|
|
6
|
-
import SrlMenu from '#components/Srl/Menu/List.vue';
|
|
7
|
-
import SrlPageDialog from '#components/Srl/Page/Dialog.vue';
|
|
8
|
-
|
|
1
|
+
import { type App } from 'vue'
|
|
9
2
|
import asyncLdComponent from './asyncLdComponent.ts';
|
|
3
|
+
import asyncSrlComponents from '#plugins/asyncSrlComponents.ts';
|
|
10
4
|
|
|
11
5
|
export default {
|
|
12
6
|
install(app: App) {
|
|
13
|
-
app
|
|
14
|
-
app.component('SrlArticleAutoload', defineComponent(SrlArticleAutoload));
|
|
15
|
-
app.component('SrlArticleRoot', defineComponent(SrlArticleRoot));
|
|
16
|
-
app.component(
|
|
17
|
-
'SrlArticleDialogButton',
|
|
18
|
-
defineComponent(SrlArticleDialogButton),
|
|
19
|
-
);
|
|
20
|
-
app.component('SrlPageDialog', defineComponent(SrlPageDialog));
|
|
21
|
-
app.component('SrlMenu', defineComponent(SrlMenu));
|
|
22
|
-
app.component('SrlNoteAccordion', defineAsyncComponent(() => import('#components/Srl/Note/Accordion.vue')));
|
|
23
|
-
app.component('SrlNoteAccordionToggle', defineAsyncComponent(() => import('#components/Srl/Note/Accordion/Toggle.vue')));
|
|
24
|
-
app.component('SrlNoteAccordionContent', defineAsyncComponent(() => import('#components/Srl/Note/Accordion/Content.vue')));
|
|
7
|
+
asyncSrlComponents(app)
|
|
25
8
|
asyncLdComponent(app);
|
|
26
9
|
},
|
|
27
10
|
};
|
|
@@ -1,20 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
interface
|
|
4
|
-
app: App;
|
|
5
|
-
}
|
|
6
|
-
interface _GlobalComponents {
|
|
7
|
-
SrlAriaTabChain: (typeof import('../components/Srl/Aria/TabChain.vue'))['default'];
|
|
8
|
-
SrlArticleAutoload: (typeof import('../components/Srl/Article/Autoload.vue'))['default'];
|
|
9
|
-
SrlArticleDialogButton: (typeof import('../components/Srl/Article/DialogButton.vue'))['default'];
|
|
10
|
-
SrlArticleRoot: (typeof import('../components/Srl/Article/Root.vue'))['default'];
|
|
11
|
-
SrlMenu: (typeof import('../components/Srl/Menu/List.vue'))['default'];
|
|
12
|
-
SrlPageDialog: (typeof import('../components/Srl/Page/Dialog.vue'))['default'];
|
|
13
|
-
SrlNoteAccordion: (typeof import('../components/Srl/Note/Accordion.vue'))['default'];
|
|
14
|
-
SrlNoteAccordionToggle: (typeof import('../components/Srl/Note/Accordion/Toggle.vue'))['default'];
|
|
15
|
-
SrlNoteAccordionContent: (typeof import('../components/Srl/Note/Accordion/Content.vue'))['default'];
|
|
16
|
-
}
|
|
17
|
-
|
|
1
|
+
export {}
|
|
2
|
+
declare global {}
|
|
3
|
+
interface _GlobalComponents {}
|
|
18
4
|
declare module '@vue/runtime-core' {
|
|
19
5
|
export interface GlobalComponents extends _GlobalComponents {}
|
|
20
6
|
}
|
package/srl/types/nswow.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export {};
|
|
2
2
|
declare global {
|
|
3
|
-
|
|
3
|
+
type NsWowSettings = {
|
|
4
4
|
languages: string[];
|
|
5
5
|
defaultLanguage: string;
|
|
6
6
|
shortBreadcrumb: boolean;
|
|
@@ -10,7 +10,7 @@ declare global {
|
|
|
10
10
|
categories: string[];
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
interface NsWowArticle {
|
|
14
14
|
uuid: string;
|
|
15
15
|
name: string;
|
|
16
16
|
translatedTitle: string;
|
|
@@ -23,11 +23,11 @@ declare global {
|
|
|
23
23
|
status: string;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
interface NsWowArticles {
|
|
27
27
|
[locale: string]: NsWowArticle[];
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
type NsWowConfig = {
|
|
31
31
|
locale: string;
|
|
32
32
|
settings: NsWowSettings;
|
|
33
33
|
articles: NsWowArticles;
|
|
@@ -40,15 +40,15 @@ declare global {
|
|
|
40
40
|
};
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
type NsWowTranslations = {
|
|
44
44
|
[locale: string]: NsWowTranslation;
|
|
45
45
|
};
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
type NsWowTranslation = {
|
|
48
48
|
[key: string]: string;
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
interface NsWowMenu {
|
|
52
52
|
label: string;
|
|
53
53
|
type: string;
|
|
54
54
|
page?: string;
|
|
@@ -57,11 +57,11 @@ declare global {
|
|
|
57
57
|
submenuEntries?: NsWowMenu[];
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
interface NsWowMenus {
|
|
61
61
|
[menu: string]: NsWowMenu[];
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
interface NsWowResponseRouting {
|
|
65
65
|
version: string;
|
|
66
66
|
pages: NsWowArticle[];
|
|
67
67
|
menu: {
|
|
@@ -69,7 +69,7 @@ declare global {
|
|
|
69
69
|
};
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
interface NsWowDownload {
|
|
73
73
|
type: string;
|
|
74
74
|
title: string;
|
|
75
75
|
fileType: string;
|
|
@@ -77,19 +77,19 @@ declare global {
|
|
|
77
77
|
artifact: string;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
type NsWowDownloads = {
|
|
81
81
|
version?: string;
|
|
82
82
|
structure: NsWowDownload[];
|
|
83
83
|
annualReport?: NsWowDownload;
|
|
84
84
|
};
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
type NsWowSearchList = {
|
|
87
87
|
article: NsWowArticle;
|
|
88
88
|
href: string;
|
|
89
89
|
words: string;
|
|
90
90
|
};
|
|
91
91
|
|
|
92
|
-
|
|
92
|
+
type NsWowNavigationItem = {
|
|
93
93
|
label: string;
|
|
94
94
|
title?: string;
|
|
95
95
|
icon?: string;
|
|
@@ -116,7 +116,7 @@ declare global {
|
|
|
116
116
|
children?: NsWowNavigationItem[];
|
|
117
117
|
};
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
type NsWowPageData = {
|
|
120
120
|
time: number;
|
|
121
121
|
article: NsWowArticle | null;
|
|
122
122
|
content: string;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|