Skip to content

Commit 909b0bb

Browse files
committed
DP-3619 Responsive tables support
1 parent e5bb4dd commit 909b0bb

7 files changed

Lines changed: 224 additions & 7 deletions

File tree

‎assets/scss/dark-theme/tables.scss‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@
1818
background-color: $color-gunpowder-gray;
1919
border-bottom-color: $color-marlin-black;
2020
}
21+
22+
&.restables-clone tbody td:first-child {
23+
color: $color-white;
24+
background-color: $color-gunpowder-gray;
25+
}
2126
}
2227
}
2328

‎assets/scss/tables.scss‎

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,44 @@
3838
writing-mode: vertical-lr;
3939
}
4040
}
41-
41+
4242
}
43+
44+
&.restables-clone {
45+
display: none;
46+
width: 100%;
47+
48+
tbody {
49+
display: table;
50+
width: 100%;
51+
border-collapse: collapse;
52+
53+
+ tbody {
54+
margin-top: 10px;
55+
}
56+
57+
td {
58+
box-shadow: none;
59+
}
60+
61+
td:first-child {
62+
width: 35%;
63+
color: $color-black;
64+
font-weight: 700;
65+
background-color: $color-mist-gray;
66+
}
67+
}
68+
}
69+
}
70+
}
71+
72+
.table-responsive--stacked {
73+
table.restables-origin {
74+
display: none;
75+
}
76+
77+
table.restables-clone {
78+
display: block;
4379
}
4480
}
4581

‎docs/_index.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,10 @@ theme = ["GDCDocsTheme", "docsy"]
9292
## Reference
9393

9494
| Page | Description |
95-
|------|-------------|
95+
| ---- | ----------- |
9696
| [Markdown Reference](markdown-reference) | All Markdown formatting options with live rendered output. |
9797
| [Shortcodes](shortcodes) | Every Hugo shortcode bundled with the theme. |
98+
| [Table Examples](tables) | Live examples of all table variants, including responsive stacking for wide tables. |
9899

99100
## License
100101

‎docs/tables.md‎

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
---
2+
title: "Table Examples"
3+
linkTitle: "Table Examples"
4+
weight: 30
5+
type: docs
6+
description: "Live examples of every table variant supported by the theme — basic Markdown tables, alignment, and responsive wide tables."
7+
---
8+
9+
This page demonstrates how tables render in the GoodData Docs Theme. Every table on a docs page is automatically wrapped in a responsive container by `static/js/tables.js`. A table that does not fit its container is restacked into a two-column label/value layout by the [resTables](https://github.com/codefog/restables) plugin, with horizontal scrolling and a fade hint as the fallback for tables that cannot be restacked. All variants are styled for both the light and dark theme.
10+
11+
---
12+
13+
## Basic table
14+
15+
A standard Markdown pipe table. The header row gets a shaded background, and cells are separated by borders on all sides.
16+
17+
```markdown
18+
| Name | Type | Required | Description |
19+
|-------------|---------|----------|------------------------------------|
20+
| `workspace` | string | Yes | Workspace identifier. |
21+
| `title` | string | No | Human-readable dashboard title. |
22+
| `tags` | array | No | Tags used for filtering and search.|
23+
```
24+
25+
| Name | Type | Required | Description |
26+
|-------------|---------|----------|------------------------------------|
27+
| `workspace` | string | Yes | Workspace identifier. |
28+
| `title` | string | No | Human-readable dashboard title. |
29+
| `tags` | array | No | Tags used for filtering and search.|
30+
31+
---
32+
33+
## Column alignment
34+
35+
Control alignment with the position of `:` in the separator row.
36+
37+
```markdown
38+
| Left-aligned | Centered | Right-aligned |
39+
|:-------------|:--------:|--------------:|
40+
| Metric | Active | 1,234.56 |
41+
| Insight | Draft | 42.00 |
42+
```
43+
44+
| Left-aligned | Centered | Right-aligned |
45+
|:-------------|:--------:|--------------:|
46+
| Metric | Active | 1,234.56 |
47+
| Insight | Draft | 42.00 |
48+
49+
---
50+
51+
## Formatting inside cells
52+
53+
Cells support inline Markdown — code, emphasis, links, and even line breaks with `<br>`.
54+
55+
```markdown
56+
| Element | Example |
57+
|-----------------|--------------------------------------------------|
58+
| Inline code | `SELECT * FROM metrics` |
59+
| Bold / italic | **required**, *optional* |
60+
| Link | [GoodData website](https://www.gooddata.com) |
61+
| Multiple lines | First line<br>Second line |
62+
```
63+
64+
| Element | Example |
65+
|-----------------|--------------------------------------------------|
66+
| Inline code | `SELECT * FROM metrics` |
67+
| Bold / italic | **required**, *optional* |
68+
| Link | [GoodData website](https://www.gooddata.com) |
69+
| Multiple lines | First line<br>Second line |
70+
71+
---
72+
73+
## Responsive behavior
74+
75+
The theme makes every table responsive automatically — no shortcode or extra markup is needed. Instead of a fixed breakpoint, the theme checks whether each table actually fits its container (re-checked on every window resize):
76+
77+
- **Table fits:** it renders as a normal table, regardless of screen size.
78+
- **Table is wider than its container:** the [resTables](https://github.com/codefog/restables) plugin swaps in a stacked two-column clone of the table, where each original row becomes a group of label/value pairs — no horizontal scrolling needed. Narrow the browser window until a table on this page stops fitting to see it restack.
79+
80+
Tables with merged cells (`rowspan`/`colspan`) or without a header row cannot be mapped to label/value pairs, so they keep their original layout. When such a table overflows, it falls back to scrolling horizontally with a fade overlay on the right edge as a visual hint that more content is available.
81+
82+
The wide table below is the easiest place to see the swap — as the window narrows, it is the first to stop fitting and restack:
83+
84+
| Endpoint | Method | Authentication | Rate limit | Request body | Response | Since version | Notes |
85+
| -------- | ------ | -------------- | ---------- | ------------ | -------- | ------------- | ----- |
86+
| `/api/v1/entities/workspaces` | GET | Bearer token | 100 req/min | — | JSON:API collection of workspaces | 1.0 | Supports `include`, `filter`, and pagination query parameters. |
87+
| `/api/v1/entities/workspaces/{id}` | PUT | Bearer token | 60 req/min | JSON:API workspace document | Updated workspace entity | 1.0 | Requires the `MANAGE` permission on the workspace. |
88+
| `/api/v1/actions/workspaces/{id}/execution` | POST | Bearer token | 30 req/min | Execution definition (AFM) | Execution result handle | 1.2 | Long-running executions return `202 Accepted` with a polling URL. |
89+
| `/api/v1/layout/workspaces/{id}/logicalModel` | GET | Bearer token | 100 req/min | — | Declarative logical data model | 1.1 | Use `?includeParents=true` to include inherited datasets. |
90+
91+
---
92+
93+
## See also
94+
95+
- [Markdown Reference](markdown-reference) — all Markdown formatting options, including table syntax basics.
96+
- [Shortcodes reference](shortcodes) — GoodData-specific components that extend Markdown.

‎layouts/partials/hooks/body-end.html‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{{/* (C) 2026 GoodData Corporation */}}
22
<script src="/js/menu.js"></script>
33
<script src="/js/dropdown.js"></script>
4+
<script src="/js/restables.min.js"></script>
45
<script src="/js/tables.js"></script>
56
<script src="/js/share.js"></script>
67
<script src="/js/code-select.js"></script>

‎static/js/restables.min.js‎

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎static/js/tables.js‎

Lines changed: 75 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,87 @@
11
// (C) 2026 GoodData Corporation
22

33
$(document).ready(function () {
4+
const responsiveTable = function(wrapper) {
5+
if (wrapper.width() === 0) {
6+
return;
7+
}
8+
9+
const hasClone = wrapper.find("table.restables-clone").length > 0;
10+
11+
wrapper.removeClass("table-responsive--stacked");
12+
const table = wrapper.find("table").filter(":visible").first();
13+
const overflows = table.length > 0 &&
14+
(table[0].scrollWidth > table[0].clientWidth + 1 || table.width() > wrapper.width());
15+
16+
if (hasClone) {
17+
wrapper.toggleClass("table-responsive--stacked", overflows);
18+
}
19+
20+
const shown = wrapper.find("table").filter(":visible").first();
21+
const shownOverflows = shown.length > 0 &&
22+
(shown[0].scrollWidth > shown[0].clientWidth + 1 || shown.width() > wrapper.width());
23+
wrapper.toggleClass("table-responsive__wide", shownOverflows);
24+
};
25+
426
const responsiveTables = function() {
527
$(".table-responsive").each(function() {
6-
const wrapperWidth = $(this).width();
7-
const tableWidth = $(this).find("table").width();
8-
$(this).toggleClass("table-responsive__wide", tableWidth > wrapperWidth);
28+
responsiveTable($(this));
929
});
10-
}
30+
};
1131

1232
$(".td-content table").wrap($("<div>").addClass("table-responsive")).wrap($("<div>").addClass("table-responsive__inner"));
33+
34+
if ($.fn.resTables) {
35+
$(".td-content table").filter(function() {
36+
const table = $(this);
37+
38+
if (table.hasClass("td-initial") ||
39+
table.find("table").length > 0 || table.parents("table").length > 0 ||
40+
table.find("[rowspan], [colspan]").length > 0) {
41+
return false;
42+
}
43+
44+
const headerRows = table.find("thead tr");
45+
if (headerRows.length !== 1 || headerRows.find("td").length > 0) {
46+
return false;
47+
}
48+
const headerCount = headerRows.find("th").length;
49+
if (headerCount === 0) {
50+
return false;
51+
}
52+
53+
const bodyRows = table.find("tbody tr");
54+
let regular = bodyRows.length > 0;
55+
bodyRows.each(function() {
56+
const row = $(this);
57+
if (row.find("th").length > 0 || row.find("td").length !== headerCount) {
58+
regular = false;
59+
return false;
60+
}
61+
});
62+
return regular;
63+
}).resTables();
64+
}
65+
1366
responsiveTables();
14-
$(window).on("resize", responsiveTables);
67+
68+
if (window.ResizeObserver) {
69+
const observer = new ResizeObserver(function(entries) {
70+
entries.forEach(function(entry) {
71+
const wrapper = $(entry.target);
72+
const width = entry.contentRect.width;
73+
if (wrapper.data("responsiveWidth") !== width) {
74+
wrapper.data("responsiveWidth", width);
75+
responsiveTable(wrapper);
76+
}
77+
});
78+
});
79+
$(".table-responsive").each(function() {
80+
observer.observe(this);
81+
});
82+
} else {
83+
$(window).on("resize", responsiveTables);
84+
}
1585

1686
// Vertical column in tables - wrap around span
1787
const verticalColumn = document.querySelector("tbody tr:first-child td[rowspan]:first-child");

0 commit comments

Comments
 (0)