lutaml 0.10.7 → 0.10.8
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.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +2 -40
- data/lib/lutaml/uml_repository/static_site/generator.rb +30 -0
- data/lib/lutaml/version.rb +1 -1
- data/templates/static_site/assets/images/lutaml-full.svg +1 -0
- data/templates/static_site/assets/images/lutaml-icon.svg +1 -0
- data/templates/static_site/assets/scripts/ui/sidebar.js +57 -148
- data/templates/static_site/assets/styles/00-variables.css +128 -128
- data/templates/static_site/assets/styles/01-reset.css +20 -30
- data/templates/static_site/assets/styles/02-base.css +105 -110
- data/templates/static_site/assets/styles/03-layout.css +51 -101
- data/templates/static_site/assets/styles/04-components.css +636 -587
- data/templates/static_site/assets/styles/05-utilities.css +8 -74
- data/templates/static_site/assets/styles/06-diagrams.css +42 -293
- data/templates/static_site/components/content.liquid +225 -322
- data/templates/static_site/components/header.liquid +99 -119
- data/templates/static_site/components/sidebar.liquid +69 -39
- data/templates/static_site/multi_file.liquid +9 -6
- data/templates/static_site/single_file.liquid +9 -4
- metadata +3 -1
|
@@ -1,110 +1,97 @@
|
|
|
1
|
-
<div class="content-
|
|
1
|
+
<div class="content-area">
|
|
2
2
|
<!-- Welcome Screen -->
|
|
3
3
|
<div x-show="currentView === 'welcome'" x-transition class="view-welcome">
|
|
4
|
-
<
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
</div>
|
|
13
|
-
<div class="stat-card">
|
|
14
|
-
<div class="stat-value" x-text="data.metadata.statistics.classes"></div>
|
|
15
|
-
<div class="stat-label">Classes</div>
|
|
16
|
-
</div>
|
|
17
|
-
<div class="stat-card">
|
|
18
|
-
<div class="stat-value" x-text="data.metadata.statistics.attributes"></div>
|
|
19
|
-
<div class="stat-label">Attributes</div>
|
|
20
|
-
</div>
|
|
21
|
-
<div class="stat-card">
|
|
22
|
-
<div class="stat-value" x-text="data.metadata.statistics.associations"></div>
|
|
23
|
-
<div class="stat-label">Associations</div>
|
|
24
|
-
</div>
|
|
4
|
+
<span class="welcome-logo">{{ lutamlIcon }}</span>
|
|
5
|
+
<h1 class="welcome-title" x-text="JSON.parse(config).title || 'UML Model Browser'"></h1>
|
|
6
|
+
<p class="welcome-subtitle">Browse packages, classes, associations, and diagrams.</p>
|
|
7
|
+
|
|
8
|
+
<div class="welcome-stats" x-show="data && data.metadata">
|
|
9
|
+
<div class="welcome-stat">
|
|
10
|
+
<div class="welcome-stat-value" x-text="data.metadata.statistics.packages"></div>
|
|
11
|
+
<div class="welcome-stat-label">Packages</div>
|
|
25
12
|
</div>
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
<
|
|
29
|
-
|
|
13
|
+
<div class="welcome-stat">
|
|
14
|
+
<div class="welcome-stat-value" x-text="data.metadata.statistics.classes"></div>
|
|
15
|
+
<div class="welcome-stat-label">Classes</div>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="welcome-stat">
|
|
18
|
+
<div class="welcome-stat-value" x-text="data.metadata.statistics.attributes"></div>
|
|
19
|
+
<div class="welcome-stat-label">Attributes</div>
|
|
30
20
|
</div>
|
|
21
|
+
<div class="welcome-stat">
|
|
22
|
+
<div class="welcome-stat-value" x-text="data.metadata.statistics.associations"></div>
|
|
23
|
+
<div class="welcome-stat-label">Associations</div>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<div class="welcome-actions">
|
|
28
|
+
Select a package from the sidebar or press <kbd>/</kbd> to search.
|
|
31
29
|
</div>
|
|
32
30
|
</div>
|
|
33
31
|
|
|
34
|
-
<!-- Package Details
|
|
32
|
+
<!-- Package Details -->
|
|
35
33
|
<div x-show="currentView === 'package'" x-transition class="view-package">
|
|
36
34
|
<template x-if="currentPackage && data.packages[currentPackage]">
|
|
37
35
|
<div class="package-details" x-data="{ get pkg() { return $store.app.data.packages[$store.app.currentPackage]; } }">
|
|
38
36
|
<div class="entity-header">
|
|
39
|
-
<
|
|
40
|
-
|
|
37
|
+
<div class="entity-title">
|
|
38
|
+
<h1 class="entity-name" x-text="pkg.name"></h1>
|
|
39
|
+
<p class="entity-subtitle" x-show="pkg.path"><code x-text="pkg.path"></code></p>
|
|
40
|
+
</div>
|
|
41
|
+
<span class="entity-badge badge-package">Package</span>
|
|
41
42
|
</div>
|
|
42
43
|
|
|
43
|
-
<
|
|
44
|
-
<
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
</template>
|
|
54
|
-
</dd>
|
|
55
|
-
</div>
|
|
56
|
-
</template>
|
|
57
|
-
</dl>
|
|
44
|
+
<div class="entity-metadata" x-show="pkg.stereotypes && pkg.stereotypes.length > 0">
|
|
45
|
+
<div class="metadata-item">
|
|
46
|
+
<span class="metadata-label">Stereotypes</span>
|
|
47
|
+
<span class="metadata-value">
|
|
48
|
+
<template x-for="s in pkg.stereotypes" :key="s">
|
|
49
|
+
<span class="stereotype-tag" x-text="s"></span>
|
|
50
|
+
</template>
|
|
51
|
+
</span>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
58
54
|
|
|
59
55
|
<div class="entity-definition" x-show="pkg.definition">
|
|
60
|
-
<h3>Description</h3>
|
|
61
56
|
<div class="definition-content" x-html="pkg.definition"></div>
|
|
62
57
|
</div>
|
|
63
58
|
|
|
64
59
|
<!-- Empty State -->
|
|
65
60
|
<template x-if="(!pkg.subPackages || pkg.subPackages.length === 0) && (!pkg.classes || pkg.classes.length === 0) && (!pkg.diagrams || pkg.diagrams.length === 0)">
|
|
66
61
|
<div class="empty-state">
|
|
67
|
-
<p
|
|
62
|
+
<p>This package is empty.</p>
|
|
68
63
|
</div>
|
|
69
64
|
</template>
|
|
70
65
|
|
|
71
|
-
<!-- Diagrams
|
|
66
|
+
<!-- Diagrams -->
|
|
72
67
|
<div class="section" x-show="pkg.diagrams && pkg.diagrams.length > 0">
|
|
73
|
-
<h3>Diagrams
|
|
74
|
-
<
|
|
68
|
+
<h3 class="section-title">Diagrams <span class="section-count" x-text="pkg.diagrams.length"></span></h3>
|
|
69
|
+
<div class="item-list">
|
|
75
70
|
<template x-for="diagramId in pkg.diagrams" :key="diagramId">
|
|
76
|
-
<
|
|
77
|
-
<svg class="item-icon"
|
|
78
|
-
<rect x="
|
|
79
|
-
<
|
|
80
|
-
<line x1="9" y1="21" x2="9" y2="9"></line>
|
|
71
|
+
<div class="list-item" @click="$store.app.selectDiagram(diagramId)">
|
|
72
|
+
<svg class="list-item-icon" width="16" height="16" viewBox="0 0 16 16" fill="none">
|
|
73
|
+
<rect x="2" y="2" width="12" height="12" rx="1.5" stroke="currentColor" stroke-width="1.3"/>
|
|
74
|
+
<path d="M2 6h12M6 6v8" stroke="currentColor" stroke-width="1.3"/>
|
|
81
75
|
</svg>
|
|
82
|
-
<span class="
|
|
83
|
-
<span class="
|
|
84
|
-
<span class="diagram
|
|
85
|
-
</
|
|
76
|
+
<span class="list-item-name" x-text="$store.app.data.diagrams[diagramId] && $store.app.data.diagrams[diagramId].name"></span>
|
|
77
|
+
<span class="list-item-meta" x-show="$store.app.data.diagrams[diagramId] && $store.app.data.diagrams[diagramId].objectCount" x-text="`${$store.app.data.diagrams[diagramId].objectCount} objects`"></span>
|
|
78
|
+
<span class="badge badge-diagram" x-show="$store.app.data.diagrams[diagramId]" x-text="$store.app.data.diagrams[diagramId] && $store.app.data.diagrams[diagramId].type"></span>
|
|
79
|
+
</div>
|
|
86
80
|
</template>
|
|
87
|
-
</ul>
|
|
88
|
-
</div>
|
|
89
|
-
|
|
90
|
-
<!-- Info message -->
|
|
91
|
-
<template x-if="(!pkg.classes || pkg.classes.length === 0) && pkg.diagrams && pkg.diagrams.length > 0">
|
|
92
|
-
<div class="info-message">
|
|
93
|
-
<p>This package contains <strong x-text="pkg.diagrams.length"></strong> diagram(s) but no classes.</p>
|
|
94
81
|
</div>
|
|
95
|
-
</
|
|
82
|
+
</div>
|
|
96
83
|
|
|
97
84
|
<!-- Sub-packages -->
|
|
98
85
|
<div class="section" x-show="pkg.subPackages && pkg.subPackages.length > 0">
|
|
99
|
-
<h3>Sub-packages
|
|
100
|
-
<div class="
|
|
86
|
+
<h3 class="section-title">Sub-packages <span class="section-count" x-text="pkg.subPackages.length"></span></h3>
|
|
87
|
+
<div class="item-list">
|
|
101
88
|
<template x-for="subPkgId in pkg.subPackages" :key="subPkgId">
|
|
102
|
-
<div class="
|
|
103
|
-
<svg class="item-icon"
|
|
104
|
-
<path d="
|
|
89
|
+
<div class="list-item" @click="$store.app.selectPackage(subPkgId)">
|
|
90
|
+
<svg class="list-item-icon" width="16" height="16" viewBox="0 0 16 16" fill="none">
|
|
91
|
+
<path d="M2 5a2 2 0 012-2h3l1.5 2H12a2 2 0 012 2v4a2 2 0 01-2 2H4a2 2 0 01-2-2V5z" stroke="currentColor" stroke-width="1.2"/>
|
|
105
92
|
</svg>
|
|
106
|
-
<span class="item-name" x-text="data.packages[subPkgId].name"></span>
|
|
107
|
-
<span class="item-
|
|
93
|
+
<span class="list-item-name" x-text="data.packages[subPkgId].name"></span>
|
|
94
|
+
<span class="list-item-meta" x-text="`${(data.packages[subPkgId].classes || []).length} classes`"></span>
|
|
108
95
|
</div>
|
|
109
96
|
</template>
|
|
110
97
|
</div>
|
|
@@ -112,41 +99,50 @@
|
|
|
112
99
|
|
|
113
100
|
<!-- Classes -->
|
|
114
101
|
<div class="section" x-show="pkg.classes && pkg.classes.length > 0">
|
|
115
|
-
<h3>Classes
|
|
116
|
-
<
|
|
117
|
-
<
|
|
118
|
-
<
|
|
119
|
-
<
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
</thead>
|
|
125
|
-
<tbody>
|
|
126
|
-
<template x-for="classId in pkg.classes" :key="classId">
|
|
127
|
-
<tr @click="$store.app.selectClass(classId)" class="clickable-row">
|
|
128
|
-
<td><button class="link-button" x-text="data.classes[classId].name"></button></td>
|
|
129
|
-
<td><span class="type-badge" x-text="data.classes[classId].type"></span></td>
|
|
130
|
-
<td>
|
|
131
|
-
<template x-if="data.classes[classId].stereotypes && data.classes[classId].stereotypes.length > 0">
|
|
132
|
-
<div class="stereotypes-cell">
|
|
133
|
-
<template x-for="stereotype in data.classes[classId].stereotypes" :key="stereotype">
|
|
134
|
-
<span class="stereotype-tag" x-text="stereotype"></span>
|
|
135
|
-
</template>
|
|
136
|
-
</div>
|
|
137
|
-
</template>
|
|
138
|
-
</td>
|
|
139
|
-
<td><span class="count-value" x-text="(data.classes[classId].attributes || []).length"></span></td>
|
|
102
|
+
<h3 class="section-title">Classes <span class="section-count" x-text="pkg.classes.length"></span></h3>
|
|
103
|
+
<div class="table-wrapper">
|
|
104
|
+
<table class="data-table">
|
|
105
|
+
<thead>
|
|
106
|
+
<tr>
|
|
107
|
+
<th>Name</th>
|
|
108
|
+
<th>Type</th>
|
|
109
|
+
<th>Stereotypes</th>
|
|
110
|
+
<th>Attrs</th>
|
|
140
111
|
</tr>
|
|
141
|
-
</
|
|
142
|
-
|
|
143
|
-
|
|
112
|
+
</thead>
|
|
113
|
+
<tbody>
|
|
114
|
+
<template x-for="classId in pkg.classes" :key="classId">
|
|
115
|
+
<tr @click="$store.app.selectClass(classId)" class="clickable-row">
|
|
116
|
+
<td><button class="link-button" x-text="data.classes[classId].name"></button></td>
|
|
117
|
+
<td><span class="badge" :class="'badge-' + (data.classes[classId].type === 'Enumeration' ? 'enum' : data.classes[classId].type === 'DataType' ? 'datatype' : 'class')" x-text="data.classes[classId].type"></span></td>
|
|
118
|
+
<td>
|
|
119
|
+
<template x-if="data.classes[classId].stereotypes && data.classes[classId].stereotypes.length > 0">
|
|
120
|
+
<span>
|
|
121
|
+
<template x-for="st in data.classes[classId].stereotypes" :key="st">
|
|
122
|
+
<span class="stereotype-tag" x-text="st"></span>
|
|
123
|
+
</template>
|
|
124
|
+
</span>
|
|
125
|
+
</template>
|
|
126
|
+
</td>
|
|
127
|
+
<td style="color: var(--text-muted); font-variant-numeric: tabular-nums;" x-text="(data.classes[classId].attributes || []).length"></td>
|
|
128
|
+
</tr>
|
|
129
|
+
</template>
|
|
130
|
+
</tbody>
|
|
131
|
+
</table>
|
|
132
|
+
</div>
|
|
144
133
|
</div>
|
|
134
|
+
|
|
135
|
+
<!-- Info message -->
|
|
136
|
+
<template x-if="(!pkg.classes || pkg.classes.length === 0) && pkg.diagrams && pkg.diagrams.length > 0">
|
|
137
|
+
<div class="info-message">
|
|
138
|
+
This package contains <strong x-text="pkg.diagrams.length"></strong> diagram(s) but no classes.
|
|
139
|
+
</div>
|
|
140
|
+
</template>
|
|
145
141
|
</div>
|
|
146
142
|
</template>
|
|
147
143
|
</div>
|
|
148
144
|
|
|
149
|
-
<!-- Class Details
|
|
145
|
+
<!-- Class Details -->
|
|
150
146
|
<div x-show="currentView === 'class'" x-transition class="view-class">
|
|
151
147
|
<template x-if="currentClass && data.classes[currentClass]">
|
|
152
148
|
<div class="class-details" x-data="{
|
|
@@ -155,14 +151,10 @@
|
|
|
155
151
|
findClassByName(name) { return window.UMLUtils.findClassByName(data, name); },
|
|
156
152
|
getAssociationEnds(assoc, cls) {
|
|
157
153
|
if (!assoc || !cls) return { local: {}, remote: {}, direction: '↔' };
|
|
158
|
-
if (assoc.source && assoc.source.class === cls.xmiId) {
|
|
159
|
-
|
|
160
|
-
} else if (assoc.target && assoc.target.class === cls.xmiId) {
|
|
161
|
-
return { local: assoc.target, remote: assoc.source, direction: '←' };
|
|
162
|
-
}
|
|
154
|
+
if (assoc.source && assoc.source.class === cls.xmiId) return { local: assoc.source, remote: assoc.target, direction: '→' };
|
|
155
|
+
if (assoc.target && assoc.target.class === cls.xmiId) return { local: assoc.target, remote: assoc.source, direction: '←' };
|
|
163
156
|
return { local: assoc.source || {}, remote: assoc.target || {}, direction: '↔' };
|
|
164
|
-
}
|
|
165
|
-
,
|
|
157
|
+
},
|
|
166
158
|
groupByParent(items) {
|
|
167
159
|
if (!items || items.length === 0) return [];
|
|
168
160
|
const groups = {};
|
|
@@ -178,164 +170,131 @@
|
|
|
178
170
|
<h1 class="entity-name" x-text="cls.qualifiedName"></h1>
|
|
179
171
|
<p class="entity-subtitle" x-show="cls.name !== cls.qualifiedName" x-text="`(${cls.name})`"></p>
|
|
180
172
|
</div>
|
|
181
|
-
<span class="entity-
|
|
182
|
-
<span class="
|
|
173
|
+
<span class="entity-badge" :class="'badge-' + (cls.type === 'Enumeration' ? 'enum' : cls.type === 'DataType' ? 'datatype' : cls.type === 'Interface' ? 'interface' : 'class')" x-text="cls.type"></span>
|
|
174
|
+
<span class="entity-badge badge-abstract" x-show="cls.isAbstract">Abstract</span>
|
|
183
175
|
</div>
|
|
184
176
|
|
|
185
|
-
<
|
|
186
|
-
<
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
<
|
|
191
|
-
<
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
<span class="stereotype-badge" x-text="stereotype"></span>
|
|
200
|
-
</template>
|
|
201
|
-
</dd>
|
|
202
|
-
</div>
|
|
203
|
-
</template>
|
|
204
|
-
</dl>
|
|
177
|
+
<div class="entity-metadata">
|
|
178
|
+
<div class="metadata-item">
|
|
179
|
+
<span class="metadata-label">Package</span>
|
|
180
|
+
<span class="metadata-value"><button class="link-button" @click="selectPackage(cls.package)" x-text="data.packages[cls.package] && data.packages[cls.package].name"></button></span>
|
|
181
|
+
</div>
|
|
182
|
+
<div class="metadata-item" x-show="cls.stereotypes && cls.stereotypes.length > 0">
|
|
183
|
+
<span class="metadata-label">Stereotypes</span>
|
|
184
|
+
<span class="metadata-value">
|
|
185
|
+
<template x-for="st in cls.stereotypes" :key="st">
|
|
186
|
+
<span class="stereotype-tag" x-text="st"></span>
|
|
187
|
+
</template>
|
|
188
|
+
</span>
|
|
189
|
+
</div>
|
|
190
|
+
</div>
|
|
205
191
|
|
|
206
192
|
<div class="entity-definition" x-show="cls.definition">
|
|
207
|
-
<h3>Description</h3>
|
|
208
193
|
<div class="definition-content" x-html="cls.definition"></div>
|
|
209
194
|
</div>
|
|
210
195
|
|
|
211
|
-
<!-- Inheritance
|
|
196
|
+
<!-- Inheritance -->
|
|
212
197
|
<div class="section" x-show="(cls.generalizations && cls.generalizations.length > 0) || (cls.specializations && cls.specializations.length > 0)">
|
|
213
|
-
<h3>Inheritance</h3>
|
|
198
|
+
<h3 class="section-title">Inheritance</h3>
|
|
214
199
|
|
|
215
|
-
<div x-show="cls.generalizations && cls.generalizations.length > 0">
|
|
216
|
-
<
|
|
217
|
-
<div class="
|
|
200
|
+
<div x-show="cls.generalizations && cls.generalizations.length > 0" style="margin-bottom: var(--space-4);">
|
|
201
|
+
<div class="section-title" style="font-size: var(--text-xs);">Extends</div>
|
|
202
|
+
<div class="item-list">
|
|
218
203
|
<template x-for="parentId in cls.generalizations" :key="parentId">
|
|
219
|
-
<div class="
|
|
220
|
-
<
|
|
221
|
-
<
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
</button>
|
|
226
|
-
<div class="inheritance-meta" x-show="data.classes[parentId]">
|
|
227
|
-
<span class="inheritance-path" x-text="data.classes[parentId] && data.classes[parentId].qualifiedName"></span>
|
|
228
|
-
</div>
|
|
204
|
+
<div class="list-item" @click="selectClass(parentId)">
|
|
205
|
+
<svg class="list-item-icon" width="14" height="14" viewBox="0 0 14 14" fill="none">
|
|
206
|
+
<polyline points="4 10 7 4 10 10" stroke="currentColor" stroke-width="1.3" fill="none"/>
|
|
207
|
+
</svg>
|
|
208
|
+
<span class="list-item-name" x-text="data.classes[parentId] && data.classes[parentId].name"></span>
|
|
209
|
+
<span class="list-item-meta" x-text="data.classes[parentId] && data.classes[parentId].qualifiedName"></span>
|
|
229
210
|
</div>
|
|
230
211
|
</template>
|
|
231
212
|
</div>
|
|
232
213
|
</div>
|
|
233
214
|
|
|
234
215
|
<div x-show="cls.specializations && cls.specializations.length > 0">
|
|
235
|
-
<
|
|
236
|
-
<div class="
|
|
216
|
+
<div class="section-title" style="font-size: var(--text-xs);">Extended by</div>
|
|
217
|
+
<div class="item-list">
|
|
237
218
|
<template x-for="childId in cls.specializations" :key="childId">
|
|
238
|
-
<
|
|
239
|
-
<svg class="item-icon"
|
|
240
|
-
<polyline points="
|
|
219
|
+
<div class="list-item" @click="selectClass(childId)">
|
|
220
|
+
<svg class="list-item-icon" width="14" height="14" viewBox="0 0 14 14" fill="none">
|
|
221
|
+
<polyline points="4 4 7 10 10 4" stroke="currentColor" stroke-width="1.3" fill="none"/>
|
|
241
222
|
</svg>
|
|
242
|
-
<span x-text="data.classes[childId] && data.classes[childId].name"></span>
|
|
243
|
-
</
|
|
223
|
+
<span class="list-item-name" x-text="data.classes[childId] && data.classes[childId].name"></span>
|
|
224
|
+
</div>
|
|
244
225
|
</template>
|
|
245
226
|
</div>
|
|
246
227
|
</div>
|
|
247
228
|
</div>
|
|
248
229
|
|
|
249
|
-
<!-- Attributes
|
|
230
|
+
<!-- Attributes -->
|
|
250
231
|
<div class="section" x-show="cls.attributes && cls.attributes.length > 0">
|
|
251
|
-
<h3>Attributes
|
|
252
|
-
<
|
|
253
|
-
<
|
|
254
|
-
<
|
|
255
|
-
<th>Name</th>
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
<
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
<
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
<
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
</span>
|
|
280
|
-
</
|
|
281
|
-
</
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
<span class="modifier-badge" x-show="attr.isReadOnly">readOnly</span>
|
|
287
|
-
</td>
|
|
288
|
-
</tr>
|
|
289
|
-
</template>
|
|
290
|
-
</tbody>
|
|
291
|
-
</table>
|
|
232
|
+
<h3 class="section-title">Attributes <span class="section-count" x-text="cls.attributes.length"></span></h3>
|
|
233
|
+
<div class="table-wrapper">
|
|
234
|
+
<table class="data-table">
|
|
235
|
+
<thead>
|
|
236
|
+
<tr><th>Name</th><th>Type</th><th>Visibility</th><th>Cardinality</th><th>Modifiers</th></tr>
|
|
237
|
+
</thead>
|
|
238
|
+
<tbody>
|
|
239
|
+
<template x-for="attrId in cls.attributes" :key="attrId">
|
|
240
|
+
<tr x-data="{ attr: data.attributes[attrId] }">
|
|
241
|
+
<td>
|
|
242
|
+
<code x-text="attr.name"></code>
|
|
243
|
+
<div class="cell-description" x-show="attr.definition" x-text="attr.definition"></div>
|
|
244
|
+
</td>
|
|
245
|
+
<td>
|
|
246
|
+
<template x-if="isUmlBasicType(attr.type)">
|
|
247
|
+
<code class="uml-basic-type" x-text="attr.type"></code>
|
|
248
|
+
</template>
|
|
249
|
+
<template x-if="!isUmlBasicType(attr.type) && findClassByName(attr.type)">
|
|
250
|
+
<button class="type-link" @click="selectClass(findClassByName(attr.type))" x-text="attr.type"></button>
|
|
251
|
+
</template>
|
|
252
|
+
<template x-if="!isUmlBasicType(attr.type) && !findClassByName(attr.type)">
|
|
253
|
+
<span class="type-unresolved" x-text="attr.type"></span>
|
|
254
|
+
</template>
|
|
255
|
+
</td>
|
|
256
|
+
<td><span class="visibility-badge" :data-visibility="attr.visibility" x-text="attr.visibility"></span></td>
|
|
257
|
+
<td><code x-show="attr.cardinality" x-text="`${attr.cardinality.min}..${attr.cardinality.max}`"></code></td>
|
|
258
|
+
<td>
|
|
259
|
+
<span class="modifier-badge" x-show="attr.isStatic">static</span>
|
|
260
|
+
<span class="modifier-badge" x-show="attr.isReadOnly">readOnly</span>
|
|
261
|
+
</td>
|
|
262
|
+
</tr>
|
|
263
|
+
</template>
|
|
264
|
+
</tbody>
|
|
265
|
+
</table>
|
|
266
|
+
</div>
|
|
292
267
|
</div>
|
|
293
268
|
|
|
294
|
-
<!-- Inherited Attributes
|
|
269
|
+
<!-- Inherited Attributes -->
|
|
295
270
|
<div class="section" x-show="cls.inheritedAttributes && cls.inheritedAttributes.length > 0">
|
|
296
|
-
<h3>Inherited Attributes
|
|
297
|
-
|
|
271
|
+
<h3 class="section-title">Inherited Attributes <span class="section-count" x-text="cls.inheritedAttributes.length"></span></h3>
|
|
298
272
|
<template x-for="(parentGroup, idx) in groupByParent(cls.inheritedAttributes)" :key="idx">
|
|
299
|
-
<div class="
|
|
300
|
-
<
|
|
273
|
+
<div class="inheritance-group">
|
|
274
|
+
<div class="inheritance-header">
|
|
301
275
|
<span>From:</span>
|
|
302
276
|
<button class="link-button" @click="selectClass(parentGroup[0].inheritedFrom)" x-text="parentGroup[0].inheritedFromName"></button>
|
|
303
|
-
</
|
|
277
|
+
</div>
|
|
304
278
|
<div class="table-wrapper">
|
|
305
|
-
<table class="data-table inherited-
|
|
306
|
-
<thead>
|
|
307
|
-
<tr>
|
|
308
|
-
<th>Name</th>
|
|
309
|
-
<th>Type</th>
|
|
310
|
-
<th>Visibility</th>
|
|
311
|
-
<th>Cardinality</th>
|
|
312
|
-
<th>Modifiers</th>
|
|
313
|
-
</tr>
|
|
314
|
-
</thead>
|
|
279
|
+
<table class="data-table inherited-table">
|
|
280
|
+
<thead><tr><th>Name</th><th>Type</th><th>Visibility</th><th>Cardinality</th></tr></thead>
|
|
315
281
|
<tbody>
|
|
316
282
|
<template x-for="item in parentGroup" :key="item.attributeId">
|
|
317
283
|
<tr x-data="{ attr: item.attribute }">
|
|
318
|
-
<td>
|
|
319
|
-
<code x-text="attr.name"></code>
|
|
320
|
-
<div class="cell-description" x-show="attr.definition" x-text="attr.definition"></div>
|
|
321
|
-
</td>
|
|
284
|
+
<td><code x-text="attr.name"></code></td>
|
|
322
285
|
<td>
|
|
323
286
|
<template x-if="isUmlBasicType(attr.type)">
|
|
324
|
-
<code class="
|
|
287
|
+
<code class="uml-basic-type" x-text="attr.type"></code>
|
|
325
288
|
</template>
|
|
326
289
|
<template x-if="!isUmlBasicType(attr.type) && findClassByName(attr.type)">
|
|
327
290
|
<button class="type-link" @click="selectClass(findClassByName(attr.type))" x-text="attr.type"></button>
|
|
328
291
|
</template>
|
|
329
292
|
<template x-if="!isUmlBasicType(attr.type) && !findClassByName(attr.type)">
|
|
330
|
-
<span class="type-unresolved"
|
|
293
|
+
<span class="type-unresolved" x-text="attr.type"></span>
|
|
331
294
|
</template>
|
|
332
295
|
</td>
|
|
333
296
|
<td><span class="visibility-badge" :data-visibility="attr.visibility" x-text="attr.visibility"></span></td>
|
|
334
297
|
<td><code x-show="attr.cardinality" x-text="`${attr.cardinality.min}..${attr.cardinality.max}`"></code></td>
|
|
335
|
-
<td>
|
|
336
|
-
<span class="modifier-badge" x-show="attr.isStatic">static</span>
|
|
337
|
-
<span class="modifier-badge" x-show="attr.isReadOnly">readOnly</span>
|
|
338
|
-
</td>
|
|
339
298
|
</tr>
|
|
340
299
|
</template>
|
|
341
300
|
</tbody>
|
|
@@ -345,44 +304,28 @@
|
|
|
345
304
|
</template>
|
|
346
305
|
</div>
|
|
347
306
|
|
|
348
|
-
<!-- Associations
|
|
307
|
+
<!-- Associations -->
|
|
349
308
|
<div class="section" x-show="cls.associations && cls.associations.length > 0">
|
|
350
|
-
<h3>Associations
|
|
309
|
+
<h3 class="section-title">Associations <span class="section-count" x-text="cls.associations.length"></span></h3>
|
|
351
310
|
<div class="table-wrapper">
|
|
352
|
-
<table class="data-table
|
|
353
|
-
<thead>
|
|
354
|
-
<tr>
|
|
355
|
-
<th>Name (Local Role)</th>
|
|
356
|
-
<th>Target</th>
|
|
357
|
-
<th>Dir</th>
|
|
358
|
-
<th>Cardinality</th>
|
|
359
|
-
<th>Target Role</th>
|
|
360
|
-
<th>Target Card</th>
|
|
361
|
-
<th>Type</th>
|
|
362
|
-
</tr>
|
|
363
|
-
</thead>
|
|
311
|
+
<table class="data-table">
|
|
312
|
+
<thead><tr><th>Role</th><th>Target</th><th>Dir</th><th>Cardinality</th><th>Target Role</th><th>Target Card</th><th>Type</th></tr></thead>
|
|
364
313
|
<tbody>
|
|
365
314
|
<template x-for="assocId in cls.associations" :key="assocId">
|
|
366
315
|
<tr x-data="{
|
|
367
316
|
assoc: data.associations[assocId],
|
|
368
317
|
get ends() {
|
|
369
318
|
if (!this.assoc || !cls) return { local: {}, remote: {}, direction: '↔' };
|
|
370
|
-
if (this.assoc.source && this.assoc.source.class === cls.xmiId) {
|
|
371
|
-
|
|
372
|
-
} else if (this.assoc.target && this.assoc.target.class === cls.xmiId) {
|
|
373
|
-
return { local: this.assoc.target, remote: this.assoc.source, direction: '←' };
|
|
374
|
-
}
|
|
319
|
+
if (this.assoc.source && this.assoc.source.class === cls.xmiId) return { local: this.assoc.source, remote: this.assoc.target, direction: '→' };
|
|
320
|
+
if (this.assoc.target && this.assoc.target.class === cls.xmiId) return { local: this.assoc.target, remote: this.assoc.source, direction: '←' };
|
|
375
321
|
return { local: this.assoc.source || {}, remote: this.assoc.target || {}, direction: '↔' };
|
|
376
322
|
}
|
|
377
323
|
}">
|
|
378
324
|
<td>
|
|
379
325
|
<code x-text="ends.local ? (ends.local.role || '(unnamed)') : ''"></code>
|
|
380
|
-
<div class="cell-description" x-show="assoc && assoc.name && assoc.name !== (ends.local && ends.local.role)" x-text="assoc ? `Association: ${assoc.name}` : ''"></div>
|
|
381
326
|
<div class="cell-description" x-show="assoc && assoc.definition" x-text="assoc ? assoc.definition : ''"></div>
|
|
382
327
|
</td>
|
|
383
|
-
<td>
|
|
384
|
-
<button class="link-button" @click="ends.remote && ends.remote.class && selectClass(ends.remote.class)" x-text="ends.remote ? ends.remote.className : ''"></button>
|
|
385
|
-
</td>
|
|
328
|
+
<td><button class="link-button" @click="ends.remote && ends.remote.class && selectClass(ends.remote.class)" x-text="ends.remote ? ends.remote.className : ''"></button></td>
|
|
386
329
|
<td><span x-text="ends.direction"></span></td>
|
|
387
330
|
<td><code x-show="ends.local && ends.local.cardinality" x-text="ends.local && ends.local.cardinality ? `${ends.local.cardinality.min}..${ends.local.cardinality.max}` : ''"></code></td>
|
|
388
331
|
<td><code x-text="ends.remote ? (ends.remote.role || '(unnamed)') : ''"></code></td>
|
|
@@ -390,9 +333,7 @@
|
|
|
390
333
|
<td>
|
|
391
334
|
<span x-show="ends.local && ends.local.aggregation === 'composite'" title="Composition">◆</span>
|
|
392
335
|
<span x-show="ends.local && ends.local.aggregation === 'shared'" title="Aggregation">◇</span>
|
|
393
|
-
<span x-show="ends.
|
|
394
|
-
<span x-show="ends.remote && ends.remote.aggregation === 'shared'" title="Aggregation">◇</span>
|
|
395
|
-
<span x-show="!(ends.local && ends.local.aggregation) && !(ends.remote && ends.remote.aggregation)">Assoc</span>
|
|
336
|
+
<span x-show="!(ends.local && ends.local.aggregation) && !(ends.remote && ends.remote.aggregation)">—</span>
|
|
396
337
|
</td>
|
|
397
338
|
</tr>
|
|
398
339
|
</template>
|
|
@@ -401,62 +342,34 @@
|
|
|
401
342
|
</div>
|
|
402
343
|
</div>
|
|
403
344
|
|
|
404
|
-
<!-- Inherited Associations
|
|
345
|
+
<!-- Inherited Associations -->
|
|
405
346
|
<div class="section" x-show="cls.inheritedAssociations && cls.inheritedAssociations.length > 0">
|
|
406
|
-
<h3>Inherited Associations
|
|
407
|
-
|
|
347
|
+
<h3 class="section-title">Inherited Associations <span class="section-count" x-text="cls.inheritedAssociations.length"></span></h3>
|
|
408
348
|
<template x-for="(parentGroup, idx) in groupByParent(cls.inheritedAssociations)" :key="idx">
|
|
409
|
-
<div class="
|
|
410
|
-
<
|
|
349
|
+
<div class="inheritance-group">
|
|
350
|
+
<div class="inheritance-header">
|
|
411
351
|
<span>From:</span>
|
|
412
352
|
<button class="link-button" @click="selectClass(parentGroup[0].inheritedFrom)" x-text="parentGroup[0].inheritedFromName"></button>
|
|
413
|
-
</
|
|
353
|
+
</div>
|
|
414
354
|
<div class="table-wrapper">
|
|
415
|
-
<table class="data-table inherited-
|
|
416
|
-
<thead>
|
|
417
|
-
<tr>
|
|
418
|
-
<th>Name (Local Role)</th>
|
|
419
|
-
<th>Target</th>
|
|
420
|
-
<th>Dir</th>
|
|
421
|
-
<th>Cardinality</th>
|
|
422
|
-
<th>Target Role</th>
|
|
423
|
-
<th>Target Card</th>
|
|
424
|
-
<th>Type</th>
|
|
425
|
-
</tr>
|
|
426
|
-
</thead>
|
|
355
|
+
<table class="data-table inherited-table">
|
|
356
|
+
<thead><tr><th>Role</th><th>Target</th><th>Dir</th><th>Cardinality</th><th>Target Role</th></tr></thead>
|
|
427
357
|
<tbody>
|
|
428
358
|
<template x-for="item in parentGroup" :key="item.associationId">
|
|
429
359
|
<tr x-data="{
|
|
430
360
|
assoc: data.associations[item.associationId],
|
|
431
361
|
get ends() {
|
|
432
362
|
if (!this.assoc || !cls) return { local: {}, remote: {}, direction: '↔' };
|
|
433
|
-
if (this.assoc.source && this.assoc.source.class === cls.xmiId) {
|
|
434
|
-
|
|
435
|
-
} else if (this.assoc.target && this.assoc.target.class === cls.xmiId) {
|
|
436
|
-
return { local: this.assoc.target, remote: this.assoc.source, direction: '←' };
|
|
437
|
-
}
|
|
363
|
+
if (this.assoc.source && this.assoc.source.class === cls.xmiId) return { local: this.assoc.source, remote: this.assoc.target, direction: '→' };
|
|
364
|
+
if (this.assoc.target && this.assoc.target.class === cls.xmiId) return { local: this.assoc.target, remote: this.assoc.source, direction: '←' };
|
|
438
365
|
return { local: this.assoc.source || {}, remote: this.assoc.target || {}, direction: '↔' };
|
|
439
366
|
}
|
|
440
367
|
}">
|
|
441
|
-
<td>
|
|
442
|
-
|
|
443
|
-
<div class="cell-description" x-show="assoc && assoc.name" x-text="assoc ? `Association: ${assoc.name}` : ''"></div>
|
|
444
|
-
<div class="cell-description" x-show="assoc && assoc.definition" x-text="assoc ? assoc.definition : ''"></div>
|
|
445
|
-
</td>
|
|
446
|
-
<td>
|
|
447
|
-
<button class="link-button" @click="ends.remote && ends.remote.class && selectClass(ends.remote.class)" x-text="ends.remote ? ends.remote.className : ''"></button>
|
|
448
|
-
</td>
|
|
368
|
+
<td><code x-text="ends.local ? (ends.local.role || '(unnamed)') : ''"></code></td>
|
|
369
|
+
<td><button class="link-button" @click="ends.remote && ends.remote.class && selectClass(ends.remote.class)" x-text="ends.remote ? ends.remote.className : ''"></button></td>
|
|
449
370
|
<td><span x-text="ends.direction"></span></td>
|
|
450
371
|
<td><code x-show="ends.local && ends.local.cardinality" x-text="ends.local && ends.local.cardinality ? `${ends.local.cardinality.min}..${ends.local.cardinality.max}` : ''"></code></td>
|
|
451
372
|
<td><code x-text="ends.remote ? (ends.remote.role || '(unnamed)') : ''"></code></td>
|
|
452
|
-
<td><code x-show="ends.remote && ends.remote.cardinality" x-text="ends.remote && ends.remote.cardinality ? `${ends.remote.cardinality.min}..${ends.remote.cardinality.max}` : ''"></code></td>
|
|
453
|
-
<td>
|
|
454
|
-
<span x-show="ends.local && ends.local.aggregation === 'composite'">◆</span>
|
|
455
|
-
<span x-show="ends.local && ends.local.aggregation === 'shared'">◇</span>
|
|
456
|
-
<span x-show="ends.remote && ends.remote.aggregation === 'composite'">◆</span>
|
|
457
|
-
<span x-show="ends.remote && ends.remote.aggregation === 'shared'">◇</span>
|
|
458
|
-
<span x-show="!(ends.local && ends.local.aggregation) && !(ends.remote && ends.remote.aggregation)">Assoc</span>
|
|
459
|
-
</td>
|
|
460
373
|
</tr>
|
|
461
374
|
</template>
|
|
462
375
|
</tbody>
|
|
@@ -472,31 +385,24 @@
|
|
|
472
385
|
<!-- Search Results -->
|
|
473
386
|
<div x-show="currentView === 'search'" x-transition class="view-search">
|
|
474
387
|
<div x-data="searchResultsView">
|
|
475
|
-
<h2>Search Results</h2>
|
|
476
|
-
<p
|
|
388
|
+
<h2 style="margin-bottom: var(--space-2);">Search Results</h2>
|
|
389
|
+
<p style="color: var(--text-muted); margin-bottom: var(--space-6); font-size: var(--text-sm);">
|
|
390
|
+
Showing results for "<strong x-text="searchQuery"></strong>"
|
|
391
|
+
</p>
|
|
477
392
|
|
|
478
|
-
<div x-show="searchResults.length === 0" class="
|
|
393
|
+
<div x-show="searchResults.length === 0" class="empty-state">
|
|
479
394
|
<p>No results found.</p>
|
|
480
395
|
</div>
|
|
481
396
|
|
|
482
|
-
<div x-show="searchResults.length > 0"
|
|
397
|
+
<div x-show="searchResults.length > 0">
|
|
483
398
|
<template x-for="group in groupedResults" :key="group.type">
|
|
484
399
|
<div class="result-group">
|
|
485
|
-
<h3 x-text="`${group.type}s (${group.items.length})`"></h3>
|
|
486
|
-
|
|
487
|
-
<div class="result-list">
|
|
400
|
+
<h3 class="result-group-title" x-text="`${group.type}s (${group.items.length})`"></h3>
|
|
401
|
+
<div class="item-list">
|
|
488
402
|
<template x-for="result in group.items" :key="result.id">
|
|
489
|
-
<div class="
|
|
490
|
-
<
|
|
491
|
-
|
|
492
|
-
<span class="result-score" :title="`Relevance: ${result.score.toFixed(2)}`">
|
|
493
|
-
<div class="score-dot" :class="getScoreClass(result.score)"></div>
|
|
494
|
-
</span>
|
|
495
|
-
</div>
|
|
496
|
-
<div class="result-details">
|
|
497
|
-
<span class="result-type" x-text="result.entityType"></span>
|
|
498
|
-
<span class="result-path" x-text="result.qualifiedName || result.package"></span>
|
|
499
|
-
</div>
|
|
403
|
+
<div class="list-item" @click="openResult(result)">
|
|
404
|
+
<span class="list-item-name" x-html="highlightMatches(result.name, searchQuery)"></span>
|
|
405
|
+
<span class="list-item-meta" x-text="result.entityType"></span>
|
|
500
406
|
</div>
|
|
501
407
|
</template>
|
|
502
408
|
</div>
|
|
@@ -504,6 +410,7 @@
|
|
|
504
410
|
</template>
|
|
505
411
|
</div>
|
|
506
412
|
</div>
|
|
413
|
+
</div>
|
|
507
414
|
|
|
508
415
|
<!-- Diagram View -->
|
|
509
416
|
<div x-show="currentView === 'diagram'" x-transition class="view-diagram">
|
|
@@ -525,8 +432,8 @@
|
|
|
525
432
|
downloadSvg() {
|
|
526
433
|
const svgEl = document.querySelector('.diagram-svg-container svg');
|
|
527
434
|
if (!svgEl) return;
|
|
528
|
-
const
|
|
529
|
-
const blob = new Blob([
|
|
435
|
+
const d = new XMLSerializer().serializeToString(svgEl);
|
|
436
|
+
const blob = new Blob([d], { type: 'image/svg+xml' });
|
|
530
437
|
const url = URL.createObjectURL(blob);
|
|
531
438
|
const a = document.createElement('a');
|
|
532
439
|
a.href = url; a.download = (this.diag.name || 'diagram').replace(/[^a-zA-Z0-9_-]/g, '_') + '.svg';
|
|
@@ -536,29 +443,26 @@
|
|
|
536
443
|
<div class="entity-header">
|
|
537
444
|
<div class="entity-title">
|
|
538
445
|
<h1 class="entity-name" x-text="diag.name"></h1>
|
|
539
|
-
<p class="
|
|
446
|
+
<p class="diagram-meta">
|
|
540
447
|
<span x-text="diag.type"></span>
|
|
541
|
-
<span x-show="diag.objectCount">
|
|
448
|
+
<span x-show="diag.objectCount"> · <span x-text="diag.objectCount"></span> elements, <span x-text="diag.linkCount"></span> connectors</span>
|
|
542
449
|
</p>
|
|
543
450
|
</div>
|
|
544
|
-
<div style="display: flex; gap:
|
|
545
|
-
<button class="link-button" x-show="diag.package" @click="selectPackage(diag.package)">
|
|
546
|
-
|
|
547
|
-
</button>
|
|
548
|
-
<span class="entity-type-badge">Diagram</span>
|
|
451
|
+
<div style="display: flex; gap: var(--space-2); align-items: center;">
|
|
452
|
+
<button class="link-button" x-show="diag.package" @click="selectPackage(diag.package)">← Package</button>
|
|
453
|
+
<span class="entity-badge badge-diagram">Diagram</span>
|
|
549
454
|
</div>
|
|
550
455
|
</div>
|
|
551
456
|
|
|
552
457
|
<div class="diagram-toolbar" x-show="diag.svg">
|
|
553
|
-
<button class="btn
|
|
554
|
-
<button class="btn
|
|
555
|
-
<button class="btn
|
|
556
|
-
<button class="btn
|
|
458
|
+
<button class="btn-sm" @click="zoom(1.2)">Zoom In</button>
|
|
459
|
+
<button class="btn-sm" @click="zoom(0.8)">Zoom Out</button>
|
|
460
|
+
<button class="btn-sm" @click="resetView()">Reset</button>
|
|
461
|
+
<button class="btn-sm" @click="downloadSvg()">Download SVG</button>
|
|
557
462
|
</div>
|
|
558
463
|
|
|
559
464
|
<div class="diagram-svg-container"
|
|
560
465
|
x-show="diag.svg"
|
|
561
|
-
x-ref="diagramContainer"
|
|
562
466
|
@wheel.prevent="zoom($event.deltaY > 0 ? 0.9 : 1.1)"
|
|
563
467
|
@mousedown="startPan($event)"
|
|
564
468
|
@mousemove="doPan($event)"
|
|
@@ -569,10 +473,9 @@
|
|
|
569
473
|
</div>
|
|
570
474
|
|
|
571
475
|
<div x-show="!diag.svg" class="empty-state">
|
|
572
|
-
<p
|
|
476
|
+
<p>SVG rendering not available. Re-generate with <code>--render-diagrams</code> to include SVG.</p>
|
|
573
477
|
</div>
|
|
574
478
|
</div>
|
|
575
479
|
</template>
|
|
576
480
|
</div>
|
|
577
|
-
|
|
578
|
-
</div>
|
|
481
|
+
</div>
|