diff --git a/src/css/structurizr-diagram.css b/src/css/structurizr-diagram.css
index f20cbe6..d777647 100644
--- a/src/css/structurizr-diagram.css
+++ b/src/css/structurizr-diagram.css
@@ -5,6 +5,21 @@
border-style: none;
}
+details.thumbnailGroup > summary:first-of-type {
+ display: list-item;
+ counter-increment: list-item 0;
+ list-style: inside disclosure-closed;
+}
+details.thumbnailGroup[open] > summary:first-of-type {
+ list-style-type: disclosure-open;
+}
+
+details.thumbnailGroup summary {
+ display: block;
+ unicode-bidi: isolate;
+ text-transform: capitalize;
+}
+
.diagramThumbnail {
cursor: pointer;
margin: 0 0 40px 0;
diff --git a/src/jsp/diagrams.jsp b/src/jsp/diagrams.jsp
index 383df45..f6c055e 100644
--- a/src/jsp/diagrams.jsp
+++ b/src/jsp/diagrams.jsp
@@ -588,33 +588,63 @@
function initThumbnails() {
var html = '';
var index = 1;
- views.forEach(function(view) {
- viewKeys.push(view.key);
- var id = 'diagram' + index;
- var title = structurizr.util.escapeHtml(structurizr.ui.getTitleForView(view));
- html += '
';
+ // determine view group based on view property viewGroup if present
+ const viewGroups = views.reduce((acc, view) => {
+ const viewGroup = (view.properties?.viewGroup ?? 'default').toLowerCase();
+ if (!acc[viewGroup]) {
+ acc[viewGroup] = [];
+ }
+ acc[viewGroup].push(view);
+ return acc;
+ }, { default: []});
+
+ function _renderViews(views) {
+ views.forEach(function(view) {
+ viewKeys.push(view.key);
+ var id = 'diagram' + index;
+ var title = structurizr.util.escapeHtml(structurizr.ui.getTitleForView(view));
+
+ html += '
';
+
+ if (view.type === structurizr.constants.IMAGE_VIEW_TYPE) {
+ html += '

';
+ } else {
+
+
+ html += '
';
+
+
+ html += '  + '-thumbnail.png)
';
+
+
+ }
- if (view.type === structurizr.constants.IMAGE_VIEW_TYPE) {
- html += '

';
- } else {
-
-
- html += '
';
-
-
- html += '  + '-thumbnail.png)
';
-
-
- }
+ html += '
';
+ html += title;
+ html += '
#' + structurizr.util.escapeHtml(view.key) + '';
+ html += '
';
- html += '
';
- html += title;
- html += '
#' + structurizr.util.escapeHtml(view.key) + '';
- html += '
';
+ index++;
+ });
+ }
- index++;
- });
+ // if only a single viewGroup is present, render the views directly
+ // this happends if no view has the custom property viewGroup set
+ if (Object.keys(viewGroups).length === 1) {
+ _renderViews(views);
+ } else {
+ Object.entries(viewGroups).forEach(([keyGroup, _views]) => {
+ html += '';
+ html += '' + keyGroup + '
';
+ html += '';
+
+ _renderViews(_views);
+
+ html += '
';
+ html += ' ';
+ })
+ }
$('#diagramNavigation').append(html);