pgkiln 0.40.0 → 0.42.0
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/db/migrations/095_rest_catalogs.sql +59 -0
- package/db/migrations/096_developer_email.sql +15 -0
- package/db/migrations/097_generated_app_quality.sql +911 -0
- package/db/migrations/098_app_activity.sql +37 -0
- package/docs/apex-feature-parity.md +15 -12
- package/docs/guide/03-builder.md +103 -19
- package/docs/guide/04-pages-and-regions.md +37 -4
- package/docs/guide/09-reference.md +6 -2
- package/docs/guide/11-from-apex.md +1 -1
- package/docs/guide/12-development.md +19 -2
- package/docs/guide/14-globalization.md +7 -3
- package/docs/guide/17-mobile.md +1 -1
- package/docs/guide/19-rest-data-sources.md +39 -1
- package/examples/hr/hr_59_gantt_editing.sql +21 -0
- package/examples/hr/hr_60_tree_charts.sql +46 -0
- package/package.json +1 -1
- package/public/app.css +219 -33
- package/public/app.js +206 -0
- package/public/builder.css +31 -3
- package/public/builder.js +31 -0
- package/public/sw.js +5 -2
- package/src/app.ts +6 -0
- package/src/builder/appfromfile.ts +5 -4
- package/src/builder/appsheets.ts +23 -9
- package/src/builder/appwizard.ts +215 -70
- package/src/builder/blueprints.ts +2 -1
- package/src/builder/components.ts +1 -1
- package/src/builder/find-workspace.ts +120 -0
- package/src/builder/home.ts +4 -32
- package/src/builder/mail.ts +39 -0
- package/src/builder/newapp.ts +182 -5
- package/src/builder/region-settings.ts +19 -1
- package/src/builder/rest-catalogs.ts +424 -0
- package/src/builder/routes.ts +36 -34
- package/src/builder/shared.ts +2 -0
- package/src/builder/workspace-transfer.ts +136 -0
- package/src/i18n/ar.ts +15 -0
- package/src/i18n/cs.ts +15 -0
- package/src/i18n/da.ts +15 -0
- package/src/i18n/de.ts +15 -0
- package/src/i18n/el.ts +15 -0
- package/src/i18n/es.ts +15 -0
- package/src/i18n/fi.ts +15 -0
- package/src/i18n/fr.ts +15 -0
- package/src/i18n/he.ts +15 -0
- package/src/i18n/it.ts +15 -0
- package/src/i18n/ja.ts +15 -0
- package/src/i18n/ko.ts +15 -0
- package/src/i18n/nb.ts +15 -0
- package/src/i18n/pl.ts +15 -0
- package/src/i18n/pt.ts +15 -0
- package/src/i18n/ru.ts +15 -0
- package/src/i18n/sv.ts +15 -0
- package/src/i18n/tr.ts +15 -0
- package/src/i18n/uk.ts +15 -0
- package/src/i18n/zh.ts +15 -0
- package/src/i18n.ts +30 -0
- package/src/icons.ts +2 -1
- package/src/layout.ts +2 -2
- package/src/restcatalog.ts +605 -0
- package/src/runtime/charts.ts +304 -15
- package/src/runtime/data-reporter.ts +48 -16
- package/src/runtime/devbar.ts +35 -14
- package/src/runtime/engine.ts +7 -4
- package/src/runtime/gantt-move.ts +63 -0
- package/src/runtime/locale.ts +2 -2
- package/src/runtime/regions.ts +28 -2
- package/src/runtime/render.ts +18 -4
- package/src/runtime/report.ts +15 -9
- package/src/runtime/routes.ts +39 -0
- package/src/runtime/styles.ts +5 -2
- package/src/websources.ts +11 -3
- package/src/workspace-export.ts +240 -0
|
@@ -212,7 +212,7 @@ Under **Settings → Theme**, *Theme style* is **Automatic** (follow the device,
|
|
|
212
212
|
has the same choice. The choice is saved on the account, so it applies in every application that
|
|
213
213
|
allows it. For public applications it's kept in a cookie.
|
|
214
214
|
|
|
215
|
-
## Base styles: Iris and Standard
|
|
215
|
+
## Base styles: Iris, Lavender and Standard
|
|
216
216
|
|
|
217
217
|
Every application has a **base style** (Settings → Theme → *Base style*; APEX: the Universal Theme's theme style,
|
|
218
218
|
whose default in 26.1 is *Iris*). It sets the colours of the light and the dark theme, the corners, the font and the
|
|
@@ -220,12 +220,16 @@ shadows of the whole application:
|
|
|
220
220
|
|
|
221
221
|
| Base style | Look |
|
|
222
222
|
|---|---|
|
|
223
|
-
| **Iris** (the default for new applications) |
|
|
223
|
+
| **Iris** (the default for new applications) | (0.42, like APEX 26's Iris) A white body, a dark warm-grey header (`#3a3632`) with a thin accent strip and a dark menu, a blue accent (`#2b62c4`, `#84aef2` in dark mode), 4 px corners, regions with a rule under their header, a dark primary button and a large bold page title on the body (no title band) |
|
|
224
|
+
| **Lavender** | pgkiln's Iris until 0.41: indigo accent (`#5146d8`), a deep indigo header, cool light greys, 12 px corners, softer shadows, rounded navigation items and pill-shaped primary buttons |
|
|
224
225
|
| **Standard** | pgkiln's look until 0.28: blue accent, navy header, 8 px corners. Applications created before 0.29 keep it until you change it |
|
|
225
226
|
|
|
226
227
|
The accent and header colours under Settings → Theme, and the style variants below, change the base style's
|
|
227
228
|
colours (in the light theme). Choosing a colour equal to a base style's own stores nothing, so switching the base
|
|
228
|
-
style later changes it too. All text colours of
|
|
229
|
+
style later changes it too. All text colours of the base styles meet WCAG AA contrast in light and dark mode.
|
|
230
|
+
|
|
231
|
+
New applications start in the **light** theme (Settings → Theme → *Mode*), with *Users may choose light or dark*
|
|
232
|
+
on, as in APEX.
|
|
229
233
|
|
|
230
234
|
## Style variants (Theme Roller)
|
|
231
235
|
|
package/docs/guide/17-mobile.md
CHANGED
|
@@ -10,7 +10,7 @@ the home screen with its own icon, full screen, and working on when the network
|
|
|
10
10
|
|
|
11
11
|
| Setting | What it does |
|
|
12
12
|
|---|---|
|
|
13
|
-
| Installable | Adds a web app manifest and a service worker to the application. Phones offer "Add to home screen" / "Install"; the app then opens full screen, without the browser bar |
|
|
13
|
+
| Installable | Adds a web app manifest and a service worker to the application. Phones offer "Add to home screen" / "Install"; the app then opens full screen, without the browser bar. (0.42) Where the browser offers the installation (Chrome, Edge), the header shows an **Install app** button (APEX: the navigation bar's Install App entry) |
|
|
14
14
|
| Name under the icon | The short name on the home screen (the application's name when empty) |
|
|
15
15
|
| Keep visited pages on the device | Pages a user opened are shown again when there is no connection (with a notice that they may be out of date) |
|
|
16
16
|
| Keep forms sent without a connection | Forms submitted offline are kept on the device and sent when the connection is back |
|
|
@@ -111,7 +111,7 @@ Shared Components → **REST data sources** → + Add.
|
|
|
111
111
|
| URL | `https://api.example.com/v1/cities/{city}/weather`: `{name}` is a path parameter. The host is fixed: parameters can only come after it |
|
|
112
112
|
| Method | `GET`, `POST`, `PUT`, `PATCH`, `DELETE` |
|
|
113
113
|
| Web credential | The name of a web credential, or empty |
|
|
114
|
-
| Parameters | JSON: `[{"name": "city", "in": "path", "default": "&P1_CITY.", "required": true}, {"name": "units", "in": "query", "default": "metric"}]`. `in` is `path`, `query`, `header` or `body`. Defaults may use `&ITEM.` substitutions |
|
|
114
|
+
| Parameters | JSON: `[{"name": "city", "in": "path", "default": "&P1_CITY.", "required": true}, {"name": "units", "in": "query", "default": "metric"}]`. `in` is `path`, `query`, `header` or `body`. Defaults may use `&ITEM.` substitutions. `key`: the service's own name for a query, header or body parameter when it isn't lower case with `_`, e.g. `{"name": "page_size", "in": "query", "key": "pageSize"}`; `Authorization`, `Cookie`, `Host` and the transport headers can't be header parameters |
|
|
115
115
|
| Headers | JSON: extra request headers, e.g. `{"Accept-Language": "en"}`. Not for secrets (use a web credential); `Authorization`, `Cookie`, `Host` and the transport headers can't be set |
|
|
116
116
|
| Body | For `POST`, `PUT`, `PATCH`: a JSON template, `{name}` becomes the parameter's value as a JSON string. Empty: the `body` parameters as a JSON object |
|
|
117
117
|
| Row selector | Where the rows are in the response: `items`, `data.results`, `$.list[*]`. Empty: the response itself (an array, or one object as one row) |
|
|
@@ -238,6 +238,44 @@ nothing. Two runs of one source never overlap. The last 100 runs per source are
|
|
|
238
238
|
application's synchronisations start switched off. `AUTOMATIONS=off` stops scheduled and queued
|
|
239
239
|
runs on that server.
|
|
240
240
|
|
|
241
|
+
## REST source catalogs
|
|
242
|
+
|
|
243
|
+
Workspace utilities → **REST Source Catalogs** (APEX: REST Source Catalogs) describes a web service once for the
|
|
244
|
+
workspace: a **base URL** (e.g. `https://api.example.com/v1`) and its **services**, each an endpoint with a path after
|
|
245
|
+
the base URL (`/pets/{pet_id}`), a method, and the same parameters, headers, body, row selector, columns, key columns
|
|
246
|
+
and operations as a [REST data source](#rest-data-sources). Every developer of the workspace manages its catalogs.
|
|
247
|
+
|
|
248
|
+
A catalog comes from:
|
|
249
|
+
|
|
250
|
+
- an **OpenAPI 3.x or Swagger 2.0 document** in JSON (*Import a catalog*: upload `openapi.json`, paste it, or give its
|
|
251
|
+
URL, which the server reads, so the host must be on the [allow-list](#server-configuration-and-the-allow-list));
|
|
252
|
+
- a **catalog file** downloaded from another workspace or installation (*Download* on the catalog's page);
|
|
253
|
+
- **by hand**: a name and base URL, then *Add a service*.
|
|
254
|
+
|
|
255
|
+
Reading an OpenAPI document, pgkiln takes for each `GET`, `POST`, `PUT`, `PATCH` and `DELETE` operation:
|
|
256
|
+
|
|
257
|
+
| From the document | Becomes |
|
|
258
|
+
|---|---|
|
|
259
|
+
| `operationId` (or the method and path) | The service's name, e.g. `listPets` → `LIST_PETS` |
|
|
260
|
+
| `servers[0].url` (variables at their defaults; Swagger 2: `schemes`, `host`, `basePath`) | The base URL. A relative one is read against the document's URL; or type the base URL |
|
|
261
|
+
| `path`, `query` and `header` parameters (also the path's own) | Parameters: `petId` → `pet_id`, with `"key": "petId"` when the service's name differs; a schema `default` (or an `example`) as the default |
|
|
262
|
+
| The scalar properties of a JSON request body | `body` parameters (nested objects and lists need a body template) |
|
|
263
|
+
| The JSON schema of the `200`/`201` (or `default`) response | The row selector (a list, or the list property of an object such as `items`, `data` or `results`) and the columns with their types (`integer`, `number`, `boolean`, `date`, `date-time` → `timestamp`, objects and lists → `json`) |
|
|
264
|
+
| A collection `GET /pets` with `GET`, `PUT`/`PATCH`, `DELETE /pets/{petId}` and `POST /pets` | Key columns and [write-back operations](#writing-back-from-forms-and-grids) on the collection's service, when the item's parameter names a column (`pet_id`, else `id`) |
|
|
265
|
+
|
|
266
|
+
`$ref`s inside the document and `allOf` are followed. What a data source can't use (cookie and form parameters, the
|
|
267
|
+
`Authorization` header, external `$ref`s, `HEAD` and `OPTIONS`) is listed after the import, never dropped silently.
|
|
268
|
+
YAML documents: convert them to JSON first (most services offer `openapi.json` too).
|
|
269
|
+
|
|
270
|
+
**Making a data source from a catalog**: an application's Shared Components → REST data sources → + Add shows *From a
|
|
271
|
+
REST source catalog* when the application's workspace has catalogs: pick a service, optionally another name and one
|
|
272
|
+
of the application's web credentials. The data source is a **copy** (URL = base URL + path): changing or deleting the
|
|
273
|
+
catalog later doesn't change it, and *Replace from a document* on a catalog's page replaces only the catalog's
|
|
274
|
+
services. Credentials never belong to a catalog: each application signs in with its own web credential.
|
|
275
|
+
|
|
276
|
+
Catalogs belong to the workspace (migration 095): they are not part of an application's export, but of the
|
|
277
|
+
[workspace export](03-builder.md#export-and-import).
|
|
278
|
+
|
|
241
279
|
## The `invoke_api` process
|
|
242
280
|
|
|
243
281
|
A page process of type `invoke_api` ([chapter 6](06-processing.md#processes)) calls a web service.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
-- =====================================================================
|
|
2
|
+
-- HR example, part 59: dragging tasks on a Gantt chart
|
|
3
|
+
-- (docs/guide/04-pages-and-regions.md, chart regions)
|
|
4
|
+
--
|
|
5
|
+
-- The office move on page 32 "Project plan" (part 35) becomes editable for
|
|
6
|
+
-- managers: drag a task to new dates or drag its end; the arrow keys do the
|
|
7
|
+
-- same. The update runs as the application's role; a milestone (no end
|
|
8
|
+
-- date) keeps having none.
|
|
9
|
+
-- =====================================================================
|
|
10
|
+
|
|
11
|
+
grant update (starts, ends) on hr.project_task to hr_app;
|
|
12
|
+
|
|
13
|
+
update meta.region r
|
|
14
|
+
set config = r.config || jsonb_build_object(
|
|
15
|
+
'gantt_move', $q$update hr.project_task
|
|
16
|
+
set starts = :NEW_START::date,
|
|
17
|
+
ends = case when ends is null then null else :NEW_END::date end
|
|
18
|
+
where id = :TASK_ID::int$q$,
|
|
19
|
+
'gantt_move_authz', 'MANAGER')
|
|
20
|
+
from meta.page p join meta.app a on a.id = p.app_id
|
|
21
|
+
where p.id = r.page_id and a.alias = 'hr' and p.page_no = 32 and r.title = 'Office move';
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
-- =====================================================================
|
|
2
|
+
-- HR example, part 60: treemap, sunburst and timeline charts
|
|
3
|
+
-- (docs/guide/04-pages-and-regions.md, chart regions)
|
|
4
|
+
--
|
|
5
|
+
-- On page 32 "Project plan":
|
|
6
|
+
-- - a treemap of the salaries per department and job (node_id and
|
|
7
|
+
-- parent_id make the hierarchy); a department drills down to its
|
|
8
|
+
-- employees;
|
|
9
|
+
-- - a sunburst of the head count: departments, their jobs and the
|
|
10
|
+
-- employees in them;
|
|
11
|
+
-- - a timeline of the hires, a lane per department.
|
|
12
|
+
-- =====================================================================
|
|
13
|
+
|
|
14
|
+
insert into meta.region (page_id, seq, title, type, columns, template, source, config)
|
|
15
|
+
select p.id, r.seq, r.title, r.type, r.cols, r.tpl, r.source, r.config::jsonb
|
|
16
|
+
from meta.page p join meta.app a on a.id = p.app_id, (values
|
|
17
|
+
(90, 'Salaries by department and job', 'chart', 6, 'standard',
|
|
18
|
+
$q$select d.dname as "Department or job", 0 as "Salary", 'd' || d.deptno as node_id, null as parent_id, d.deptno
|
|
19
|
+
from hr.dept d
|
|
20
|
+
where exists (select 1 from hr.emp e where e.deptno = d.deptno and e.active)
|
|
21
|
+
union all
|
|
22
|
+
select initcap(e.job), sum(e.sal), 'd' || e.deptno || '-' || e.job, 'd' || e.deptno, e.deptno
|
|
23
|
+
from hr.emp e
|
|
24
|
+
where e.active
|
|
25
|
+
group by e.deptno, e.job
|
|
26
|
+
order by 3$q$,
|
|
27
|
+
'{"kind": "treemap", "link": {"page": 2, "items": {"P2_DEPTNO": "#deptno#"}}}'),
|
|
28
|
+
(100, 'Head count', 'chart', 6, 'standard',
|
|
29
|
+
$q$select d.dname as "Name", 0 as "Employees", 'd' || d.deptno as node_id, null as parent_id
|
|
30
|
+
from hr.dept d
|
|
31
|
+
where exists (select 1 from hr.emp e where e.deptno = d.deptno and e.active)
|
|
32
|
+
union all
|
|
33
|
+
select distinct initcap(e.job), 0, 'd' || e.deptno || '-' || e.job, 'd' || e.deptno
|
|
34
|
+
from hr.emp e where e.active
|
|
35
|
+
union all
|
|
36
|
+
select initcap(e.ename), 1, 'e' || e.empno, 'd' || e.deptno || '-' || e.job
|
|
37
|
+
from hr.emp e where e.active
|
|
38
|
+
order by 3$q$,
|
|
39
|
+
'{"kind": "sunburst"}'),
|
|
40
|
+
(110, 'Hires', 'chart', 12, 'standard',
|
|
41
|
+
$q$select initcap(e.ename) as "Employee", e.hiredate as "Hired", null::date as "Until", d.dname as series
|
|
42
|
+
from hr.emp e join hr.dept d using (deptno)
|
|
43
|
+
order by e.hiredate$q$,
|
|
44
|
+
'{"kind": "timeline"}')
|
|
45
|
+
) r(seq, title, type, cols, tpl, source, config)
|
|
46
|
+
where a.alias = 'hr' and p.page_no = 32;
|
package/package.json
CHANGED
package/public/app.css
CHANGED
|
@@ -76,12 +76,100 @@
|
|
|
76
76
|
color-scheme: dark;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
/* ---------- base style "Iris" (theme.base = 'iris'; the default for new
|
|
80
|
+
applications, like APEX 26's Iris theme style): (sprint 72) a light body,
|
|
81
|
+
a dark warm-grey header and menu with a thin accent strip, square-ish
|
|
82
|
+
regions with a rule under their header, 4 px corners, a dark primary button
|
|
83
|
+
and a large page title on the body. Selectors are html[data-style="iris"]:
|
|
84
|
+
they beat the Standard values above, and the application's own colours
|
|
85
|
+
(src/runtime/styles.ts, html:root, later in the page) beat them in turn.
|
|
86
|
+
Contrast: text ≥ 15:1, muted ≥ 5.8:1, accent ≥ 5.5:1, menu text ≥ 10:1. */
|
|
87
|
+
html[data-style="iris"] {
|
|
88
|
+
--bg: #ffffff;
|
|
89
|
+
--surface: #ffffff;
|
|
90
|
+
--surface-2: #f7f6f5;
|
|
91
|
+
--surface-3: #efedeb;
|
|
92
|
+
--text: #1f1c1a;
|
|
93
|
+
--muted: #645e59;
|
|
94
|
+
--border: #e2dfdc;
|
|
95
|
+
--accent: #2b62c4;
|
|
96
|
+
--accent-text: #ffffff;
|
|
97
|
+
--accent-soft: #e9f0fb;
|
|
98
|
+
--header: #3a3632;
|
|
99
|
+
--header-text: #f7f5f3;
|
|
100
|
+
--nav-bg: #2f2b28;
|
|
101
|
+
--nav-text: #ece8e4;
|
|
102
|
+
--nav-muted: #b9b2ab;
|
|
103
|
+
--nav-hover: #403b37;
|
|
104
|
+
--nav-active: #4a443f;
|
|
105
|
+
--nav-current: #ffffff;
|
|
106
|
+
--hot: #2f2b28;
|
|
107
|
+
--hot-text: #ffffff;
|
|
108
|
+
--radius: 4px;
|
|
109
|
+
--font: "Inter", "Segoe UI Variable Text", "Segoe UI", system-ui, -apple-system, Roboto, sans-serif;
|
|
110
|
+
--shadow: none;
|
|
111
|
+
}
|
|
112
|
+
@media (prefers-color-scheme: dark) {
|
|
113
|
+
html[data-style="iris"]:not([data-theme="light"]) {
|
|
114
|
+
--bg: #1a1817;
|
|
115
|
+
--surface: #232120;
|
|
116
|
+
--surface-2: #2a2826;
|
|
117
|
+
--surface-3: #33302d;
|
|
118
|
+
--text: #ece9e6;
|
|
119
|
+
--muted: #aaa49e;
|
|
120
|
+
--border: #3a3633;
|
|
121
|
+
--accent: #84aef2;
|
|
122
|
+
--accent-text: #10131a;
|
|
123
|
+
--accent-soft: #23324a;
|
|
124
|
+
--header: #121110;
|
|
125
|
+
--header-text: #ece9e6;
|
|
126
|
+
--nav-bg: #1d1b1a;
|
|
127
|
+
--nav-text: #e2ded9;
|
|
128
|
+
--nav-muted: #a39c95;
|
|
129
|
+
--nav-hover: #2c2927;
|
|
130
|
+
--nav-active: #36322f;
|
|
131
|
+
--nav-current: #ffffff;
|
|
132
|
+
--hot: #ece9e6;
|
|
133
|
+
--hot-text: #1a1817;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
html[data-style="iris"][data-theme="dark"] {
|
|
137
|
+
--bg: #1a1817;
|
|
138
|
+
--surface: #232120;
|
|
139
|
+
--surface-2: #2a2826;
|
|
140
|
+
--surface-3: #33302d;
|
|
141
|
+
--text: #ece9e6;
|
|
142
|
+
--muted: #aaa49e;
|
|
143
|
+
--border: #3a3633;
|
|
144
|
+
--accent: #84aef2;
|
|
145
|
+
--accent-text: #10131a;
|
|
146
|
+
--accent-soft: #23324a;
|
|
147
|
+
--header: #121110;
|
|
148
|
+
--header-text: #ece9e6;
|
|
149
|
+
--nav-bg: #1d1b1a;
|
|
150
|
+
--nav-text: #e2ded9;
|
|
151
|
+
--nav-muted: #a39c95;
|
|
152
|
+
--nav-hover: #2c2927;
|
|
153
|
+
--nav-active: #36322f;
|
|
154
|
+
--nav-current: #ffffff;
|
|
155
|
+
--hot: #ece9e6;
|
|
156
|
+
--hot-text: #1a1817;
|
|
157
|
+
}
|
|
158
|
+
html[data-style="iris"] .t-header { box-shadow: inset 0 3px 0 var(--accent); }
|
|
159
|
+
html[data-style="iris"] .t-nav { border-right-color: transparent; }
|
|
160
|
+
html[data-style="iris"] .t-titlebar { background: transparent; border-bottom: 0; padding: 1.25rem 1.5rem 0.25rem; }
|
|
161
|
+
html[data-style="iris"] .t-titlebar h1 { font-size: 2rem; font-weight: 700; letter-spacing: -0.02em; line-height: 1.2; }
|
|
162
|
+
html[data-style="iris"] .region-header h2 { font-size: 1.05rem; }
|
|
163
|
+
html[data-style="iris"] .btn-hot { background: var(--hot); border-color: var(--hot); color: var(--hot-text); }
|
|
164
|
+
html[data-style="iris"] .btn-hot:hover { background: color-mix(in srgb, var(--hot) 82%, var(--bg)); }
|
|
165
|
+
html[data-style="iris"] .btn-hot .btn-badge { background: var(--hot-text); color: var(--hot); }
|
|
166
|
+
|
|
79
167
|
/* ---------- base style "Iris" (theme.base = 'iris'; the default for new
|
|
80
168
|
applications, like APEX 26.1's Iris theme style). Selectors are
|
|
81
|
-
html[data-style="
|
|
169
|
+
html[data-style="lavender"]: they beat the Standard values above, and the
|
|
82
170
|
application's own colours (src/runtime/styles.ts, html:root, later in the
|
|
83
171
|
page) beat them in turn. Contrast: text ≥ 15:1, muted ≥ 5.8:1, accent ≥ 6.5:1. */
|
|
84
|
-
html[data-style="
|
|
172
|
+
html[data-style="lavender"] {
|
|
85
173
|
--bg: #f6f6fb;
|
|
86
174
|
--surface: #ffffff;
|
|
87
175
|
--surface-2: #f8f8fc;
|
|
@@ -101,7 +189,7 @@ html[data-style="iris"] {
|
|
|
101
189
|
--shadow: 0 1px 2px rgb(30 27 75 / 5%), 0 2px 8px rgb(30 27 75 / 6%);
|
|
102
190
|
}
|
|
103
191
|
@media (prefers-color-scheme: dark) {
|
|
104
|
-
html[data-style="
|
|
192
|
+
html[data-style="lavender"]:not([data-theme="light"]) {
|
|
105
193
|
--bg: #121120;
|
|
106
194
|
--surface: #1a1930;
|
|
107
195
|
--surface-2: #201f38;
|
|
@@ -119,7 +207,7 @@ html[data-style="iris"] {
|
|
|
119
207
|
--shadow: 0 1px 2px rgb(0 0 0 / 30%), 0 2px 8px rgb(0 0 0 / 25%);
|
|
120
208
|
}
|
|
121
209
|
}
|
|
122
|
-
html[data-style="
|
|
210
|
+
html[data-style="lavender"][data-theme="dark"] {
|
|
123
211
|
--bg: #121120;
|
|
124
212
|
--surface: #1a1930;
|
|
125
213
|
--surface-2: #201f38;
|
|
@@ -136,13 +224,13 @@ html[data-style="iris"][data-theme="dark"] {
|
|
|
136
224
|
--nav-active: #2a2752;
|
|
137
225
|
--shadow: 0 1px 2px rgb(0 0 0 / 30%), 0 2px 8px rgb(0 0 0 / 25%);
|
|
138
226
|
}
|
|
139
|
-
/*
|
|
140
|
-
html[data-style="
|
|
141
|
-
html[data-style="
|
|
142
|
-
html[data-style="
|
|
143
|
-
html[data-style="
|
|
144
|
-
html[data-style="
|
|
145
|
-
html[data-style="
|
|
227
|
+
/* Lavender: rounded navigation pills instead of an edge bar, quieter region headers, pill-shaped primary buttons */
|
|
228
|
+
html[data-style="lavender"] .t-nav a[aria-current="page"] { box-shadow: none; border-radius: calc(var(--radius) * 0.75); }
|
|
229
|
+
html[data-style="lavender"] .t-nav a, html[data-style="lavender"] .t-nav summary { border-radius: calc(var(--radius) * 0.75); }
|
|
230
|
+
html[data-style="lavender"] .region-header { border-bottom-color: transparent; }
|
|
231
|
+
html[data-style="lavender"] .region-header h2 { letter-spacing: -0.01em; }
|
|
232
|
+
html[data-style="lavender"] .btn-hot { border-radius: 999px; }
|
|
233
|
+
html[data-style="lavender"] :focus-visible { outline-color: var(--accent); }
|
|
146
234
|
|
|
147
235
|
* { box-sizing: border-box; }
|
|
148
236
|
html { -webkit-text-size-adjust: 100%; }
|
|
@@ -225,17 +313,18 @@ details.menu > summary::-webkit-details-marker { display: none; }
|
|
|
225
313
|
.t-nav ul ul { padding: 0 0 0 1.4rem; }
|
|
226
314
|
.t-nav a, .t-nav summary {
|
|
227
315
|
display: flex; align-items: center; gap: 0.65rem; padding: 0.5rem 0.65rem; border-radius: 6px;
|
|
228
|
-
color: var(--text); text-decoration: none; cursor: pointer; white-space: nowrap; font-size: 0.93rem;
|
|
316
|
+
color: var(--nav-text, var(--text)); text-decoration: none; cursor: pointer; white-space: nowrap; font-size: 0.93rem;
|
|
229
317
|
}
|
|
230
318
|
.t-nav summary { list-style: none; }
|
|
231
319
|
.t-nav summary::-webkit-details-marker { display: none; }
|
|
232
|
-
.t-nav summary::after { content: "›"; margin-left: auto; color: var(--muted); transition: transform 0.15s; }
|
|
320
|
+
.t-nav summary::after { content: "›"; margin-left: auto; color: var(--nav-muted, var(--muted)); transition: transform 0.15s; }
|
|
233
321
|
.t-nav details[open] > summary::after { transform: rotate(90deg); }
|
|
234
|
-
.t-nav a:hover, .t-nav summary:hover { background: var(--surface-3); }
|
|
235
|
-
|
|
236
|
-
.t-nav
|
|
237
|
-
.t-nav .
|
|
238
|
-
.t-nav
|
|
322
|
+
.t-nav a:hover, .t-nav summary:hover { background: var(--nav-hover, var(--surface-3)); }
|
|
323
|
+
/* (sprint 72) --nav-* let a style have a dark menu (Iris); without them the menu takes the page's colours */
|
|
324
|
+
.t-nav a[aria-current="page"] { background: var(--nav-active); color: var(--nav-current, var(--accent)); font-weight: 600; box-shadow: inset 3px 0 0 var(--accent); }
|
|
325
|
+
.t-nav .in-trail { color: var(--nav-current, var(--accent)); }
|
|
326
|
+
.t-nav .icon { color: var(--nav-muted, var(--muted)); }
|
|
327
|
+
.t-nav a[aria-current="page"] .icon, .t-nav .in-trail .icon { color: var(--nav-current, var(--accent)); }
|
|
239
328
|
|
|
240
329
|
/* ---------- main ---------- */
|
|
241
330
|
.t-main { min-width: 0; }
|
|
@@ -259,6 +348,9 @@ details.menu > summary::-webkit-details-marker { display: none; }
|
|
|
259
348
|
.region-hero { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 1rem 1.5rem; padding: 2rem 1.75rem; border-radius: var(--radius);
|
|
260
349
|
background: var(--accent-soft); color: var(--text); }
|
|
261
350
|
.region-hero-icon .icon { width: 3rem; height: 3rem; color: var(--accent); }
|
|
351
|
+
/* (097) the generated home page: the icon on a tile in the accent colour */
|
|
352
|
+
.region-hero-icon { display: grid; place-items: center; width: 4.5rem; height: 4.5rem; border-radius: calc(var(--radius) + 4px); background: var(--accent); }
|
|
353
|
+
.region-hero-icon .icon { width: 2.4rem; height: 2.4rem; color: var(--accent-text, #fff); }
|
|
262
354
|
.region-hero-text h2 { font-size: 1.75rem; margin: 0 0 0.35rem; }
|
|
263
355
|
.region-hero-buttons, .region-title-buttons, .region-buttons { display: flex; flex-wrap: wrap; gap: 0.5rem; }
|
|
264
356
|
@media (max-width: 640px) { .region-hero { grid-template-columns: 1fr; padding: 1.25rem 1rem; } }
|
|
@@ -401,7 +493,11 @@ details.btn-menu[open] > summary .btn-caret { transform: rotate(-90deg); }
|
|
|
401
493
|
table.report { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
|
|
402
494
|
.report th, .report td { text-align: left; padding: 0.5rem 0.7rem; border-bottom: 1px solid var(--border); white-space: nowrap; }
|
|
403
495
|
.report tbody tr:last-child td { border-bottom: 0; }
|
|
404
|
-
.report th { font-size: 0.
|
|
496
|
+
.report th { font-size: 0.85rem; color: var(--muted); background: var(--surface-2); font-weight: 650; }
|
|
497
|
+
/* (097) the edit link of a row: a pencil in a narrow first column */
|
|
498
|
+
.report th.row-edit, .report td.row-edit { width: 2.25rem; text-align: center; padding-left: 0.4rem; padding-right: 0.4rem; }
|
|
499
|
+
.report td.row-edit a { display: inline-grid; place-items: center; width: 1.9rem; height: 1.9rem; border-radius: 6px; color: var(--accent); }
|
|
500
|
+
.report td.row-edit a:hover, .report td.row-edit a:focus-visible { background: var(--accent-soft); }
|
|
405
501
|
.report th a { color: inherit; text-decoration: none; display: inline-flex; gap: 0.3rem; }
|
|
406
502
|
.report th a:hover { color: var(--accent); }
|
|
407
503
|
.sort-ind { font-size: 0.7em; }
|
|
@@ -446,7 +542,19 @@ table.report { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
|
|
|
446
542
|
.swatch { width: 10px; height: 10px; border-radius: 3px; background: var(--c); flex: none; }
|
|
447
543
|
|
|
448
544
|
/* horizontal bars */
|
|
449
|
-
.chart-bar { display: flex; flex-direction: column; gap: 0
|
|
545
|
+
.chart-bar { display: flex; flex-direction: column; gap: 0; }
|
|
546
|
+
.chart-bar > .bar-row { padding: 0.22rem 0; }
|
|
547
|
+
/* (097) gridlines behind the bars and a value axis under them */
|
|
548
|
+
.bar-stack { position: relative; }
|
|
549
|
+
.bar-grid { position: absolute; inset: -0.22rem 0; pointer-events: none; }
|
|
550
|
+
.bar-gridline { position: absolute; top: 0; bottom: 0; border-left: 1px solid var(--chart-grid); }
|
|
551
|
+
.bar-gridline.baseline { border-left-color: var(--chart-axis); }
|
|
552
|
+
.bar-stack > .bar-track { position: relative; }
|
|
553
|
+
.bar-axis { display: grid; grid-template-columns: minmax(70px, 30%) 1fr auto; gap: 0.75rem; font-size: 0.72rem; color: var(--muted); }
|
|
554
|
+
.bar-axis > :last-child { min-width: 3rem; }
|
|
555
|
+
.bar-ticks { position: relative; height: 1.1rem; }
|
|
556
|
+
.bar-ticks > span { position: absolute; top: 0.15rem; transform: translateX(-50%); font-variant-numeric: tabular-nums; white-space: nowrap; }
|
|
557
|
+
.bar-ticks > span:first-child { transform: none; }
|
|
450
558
|
.bar-row { display: grid; grid-template-columns: minmax(70px, 30%) 1fr auto; gap: 0.75rem; align-items: center; font-size: 0.88rem; }
|
|
451
559
|
.bar-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--muted); }
|
|
452
560
|
.bar-stack { display: flex; flex-direction: column; gap: 2px; }
|
|
@@ -620,6 +728,41 @@ a.drill > .polar-sector:hover { fill-opacity: 1; }
|
|
|
620
728
|
.gantt-bar:hover, .gantt-bar:focus-visible, .gantt-milestone:hover, .gantt-milestone:focus-visible { filter: brightness(1.12); }
|
|
621
729
|
.gantt-deps { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; z-index: 1; }
|
|
622
730
|
.gantt-dep { fill: none; stroke: var(--muted); stroke-width: 1.25px; }
|
|
731
|
+
/* (sprint 70) treemap, sunburst and timeline */
|
|
732
|
+
.treemap { position: relative; aspect-ratio: 16 / 10; max-height: 26rem; width: 100%; font-size: 0.78rem; }
|
|
733
|
+
.tm-group, .tm-cell { position: absolute; box-sizing: border-box; overflow: hidden; }
|
|
734
|
+
.tm-group { border: 1px solid var(--surface); }
|
|
735
|
+
.tm-title { position: absolute; top: 0; left: 0; right: 0; padding: 0.1rem 0.35rem; font-weight: 650; color: var(--text); background: color-mix(in srgb, var(--c) 42%, var(--surface)); box-shadow: inset 0 -2px 0 var(--c); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; z-index: 1; }
|
|
736
|
+
/* tinted, with the page's text colour: contrast holds in light and dark */
|
|
737
|
+
.tm-cell { display: flex; flex-direction: column; gap: 0.1rem; padding: 0.2rem 0.35rem 0.2rem 0.5rem; border: 1px solid var(--surface); background: color-mix(in srgb, var(--c) 24%, var(--surface)); box-shadow: inset 3px 0 0 var(--c); color: var(--text); text-decoration: none; }
|
|
738
|
+
.tm-leaf { background: color-mix(in srgb, var(--c) 32%, var(--surface)); }
|
|
739
|
+
.tm-cell:hover, .tm-cell:focus-visible { filter: brightness(1.12); }
|
|
740
|
+
.tm-label { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
741
|
+
.tm-value { opacity: 0.9; font-variant-numeric: tabular-nums; }
|
|
742
|
+
.sb { fill: var(--c); stroke: var(--surface); stroke-width: 0.25; }
|
|
743
|
+
.sb.d2 { fill-opacity: 0.78; } .sb.d3 { fill-opacity: 0.58; } .sb.d4 { fill-opacity: 0.4; }
|
|
744
|
+
a.drill > .sb:hover { filter: brightness(1.12); }
|
|
745
|
+
.timeline { font-size: 0.8rem; }
|
|
746
|
+
.timeline-axis { position: relative; height: 1.5rem; border-bottom: 1px solid var(--chart-axis); font-size: 0.72rem; color: var(--muted); }
|
|
747
|
+
.timeline-axis span { position: absolute; bottom: 0.3rem; padding-left: 3px; white-space: nowrap; font-variant-numeric: tabular-nums; }
|
|
748
|
+
.timeline-axis span.skip { visibility: hidden; }
|
|
749
|
+
@media (max-width: 640px) { .timeline-axis span.odd { visibility: hidden; } }
|
|
750
|
+
.timeline-lane { border-bottom: 1px solid var(--chart-grid); padding-top: 0.25rem; }
|
|
751
|
+
.timeline-name { display: block; font-size: 0.75rem; font-weight: 650; color: var(--muted); }
|
|
752
|
+
.timeline-plot { position: relative; overflow: hidden; }
|
|
753
|
+
.tl-item, .tl-point { position: absolute; display: flex; align-items: center; height: 1.4rem; color: inherit; text-decoration: none; z-index: 2; outline-offset: 2px; }
|
|
754
|
+
.tl-item { min-width: 3px; border-radius: 4px; background: color-mix(in srgb, var(--c) 30%, var(--surface)); box-shadow: inset 3px 0 0 var(--c); }
|
|
755
|
+
.tl-item .tl-label { padding: 0 0.35rem 0 0.5rem; white-space: nowrap; }
|
|
756
|
+
.tl-point { gap: 0.3rem; margin-left: -0.35rem; white-space: nowrap; }
|
|
757
|
+
.tl-dot { width: 0.7rem; height: 0.7rem; flex: none; border-radius: 50%; background: var(--c); }
|
|
758
|
+
.tl-item:hover, .tl-item:focus-visible, .tl-point:hover .tl-dot, .tl-point:focus-visible .tl-dot { filter: brightness(1.12); }
|
|
759
|
+
.gantt-editable [data-task] { cursor: grab; touch-action: none; }
|
|
760
|
+
.gantt-editable .gantt-dragging { cursor: grabbing; z-index: 3; }
|
|
761
|
+
.gantt-editable .gantt-moving { box-shadow: 0 0 0 2px var(--accent); }
|
|
762
|
+
.gantt-handle { position: absolute; top: 0; right: 0; bottom: 0; width: 8px; cursor: ew-resize; background: color-mix(in srgb, var(--surface) 45%, transparent); }
|
|
763
|
+
.gantt-editable [aria-busy="true"], .gantt-editable[aria-busy="true"] { opacity: 0.7; }
|
|
764
|
+
.gantt-status { min-height: 1.3em; margin: 0.4rem 0 0; font-size: 0.85rem; font-variant-numeric: tabular-nums; }
|
|
765
|
+
.gantt-hint { margin: 0.2rem 0 0; font-size: 0.8rem; }
|
|
623
766
|
.gantt-arrow { position: absolute; width: 0; height: 0; margin: -4px 0 0 -6px; border: 4px solid transparent; border-left: 6px solid var(--muted); border-right-width: 0; pointer-events: none; z-index: 1; }
|
|
624
767
|
|
|
625
768
|
/* data table + tooltip */
|
|
@@ -787,7 +930,7 @@ pre.source { font-family: var(--mono); font-size: 0.82rem; background: var(--sur
|
|
|
787
930
|
.card.metric { grid-template-columns: 1fr; row-gap: 0.25rem; }
|
|
788
931
|
.metric-icon { grid-row: auto; width: 36px; height: 36px; }
|
|
789
932
|
.metric-value { font-size: 1.35rem; }
|
|
790
|
-
.bar-row { grid-template-columns: minmax(60px, 35%) 1fr auto; gap: 0.5rem; }
|
|
933
|
+
.bar-row, .bar-axis { grid-template-columns: minmax(60px, 35%) 1fr auto; gap: 0.5rem; }
|
|
791
934
|
.title-row .buttons { width: 100%; }
|
|
792
935
|
.title-row .buttons .btn { flex: 1 1 auto; }
|
|
793
936
|
|
|
@@ -807,7 +950,9 @@ pre.source { font-family: var(--mono); font-size: 0.82rem; background: var(--sur
|
|
|
807
950
|
display: grid; grid-template-columns: minmax(90px, 38%) minmax(0, 1fr); gap: 0.75rem;
|
|
808
951
|
border: 0; padding: 0.3rem 0.8rem; white-space: normal; max-width: none; text-align: left !important; overflow-wrap: anywhere;
|
|
809
952
|
}
|
|
810
|
-
.report-reflow td::before { content: attr(data-label); font-size: 0.
|
|
953
|
+
.report-reflow td::before { content: attr(data-label); font-size: 0.8rem; font-weight: 650; color: var(--muted); }
|
|
954
|
+
.report-reflow td.row-edit { width: auto; text-align: left; }
|
|
955
|
+
.report-reflow td.row-edit::before { content: none; }
|
|
811
956
|
.report-reflow td.empty { display: block; }
|
|
812
957
|
.report-reflow td.empty::before { content: none; }
|
|
813
958
|
.report-reflow td.pre { white-space: pre-wrap; }
|
|
@@ -1609,6 +1754,15 @@ td.to-col-center, th.to-col-center { text-align: center; }
|
|
|
1609
1754
|
.reporter-checks { display: flex; flex-wrap: wrap; gap: 0.3rem 1rem; }
|
|
1610
1755
|
.reporter-chart { margin-bottom: 0.75rem; }
|
|
1611
1756
|
.reporter-save { margin-top: 1rem; }
|
|
1757
|
+
.reporter-hello { margin-bottom: 0.5rem; }
|
|
1758
|
+
.reporter-hello p { margin: 0.2rem 0 0; }
|
|
1759
|
+
.reporter-cards { list-style: none; margin: 0 0 0.75rem; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 14rem), 1fr)); gap: 0.6rem; }
|
|
1760
|
+
.reporter-card { display: flex; flex-direction: column; gap: 0.25rem; height: 100%; padding: 0.7rem 0.85rem; border: 1px solid var(--border); border-radius: 8px; background: var(--surface); color: inherit; text-decoration: none; }
|
|
1761
|
+
.reporter-card:hover, .reporter-card:focus-visible { border-color: var(--accent); }
|
|
1762
|
+
.reporter-card strong { color: var(--accent); }
|
|
1763
|
+
.reporter-card .muted { font-size: 0.85rem; }
|
|
1764
|
+
.reporter-card-meta { margin-top: auto; font-size: 0.78rem; color: var(--muted); }
|
|
1765
|
+
.reporter-search { max-width: 30rem; margin: 0.25rem 0 0; }
|
|
1612
1766
|
@media (max-width: 600px) {
|
|
1613
1767
|
.reporter-row > .label { flex-basis: 100%; }
|
|
1614
1768
|
}
|
|
@@ -1645,19 +1799,51 @@ dialog.crop-dialog::backdrop { background: rgb(15 20 30 / 55%); }
|
|
|
1645
1799
|
.crop-dialog .buttons { display: flex; justify-content: flex-end; gap: 0.5rem; }
|
|
1646
1800
|
|
|
1647
1801
|
/* (079) Developer toolbar: shown to developers with a builder session in the same browser.
|
|
1648
|
-
|
|
1649
|
-
.
|
|
1650
|
-
|
|
1651
|
-
.devbar
|
|
1652
|
-
|
|
1653
|
-
.
|
|
1654
|
-
.devbar
|
|
1655
|
-
.devbar
|
|
1656
|
-
|
|
1657
|
-
.devbar
|
|
1658
|
-
.devbar-
|
|
1802
|
+
(sprint 72) A compact bar of icons centred at the bottom (APEX's runtime developer toolbar);
|
|
1803
|
+
app.js docks it at the top, left or right and shrinks it to a slim tab when it is not used.
|
|
1804
|
+
The page keeps room for it, so it never covers the menu's last entry or a report's pager. */
|
|
1805
|
+
.devbar { --devbar-size: 2.75rem; position: fixed; z-index: 900; left: 50%; bottom: 0.5rem; transform: translateX(-50%);
|
|
1806
|
+
background: #1b2330; color: #fff; border-radius: 10px; box-shadow: 0 4px 16px rgb(0 0 0 / 25%); font-size: 0.8125rem;
|
|
1807
|
+
transition: transform 0.2s ease, opacity 0.2s ease; }
|
|
1808
|
+
.devbar-tools { display: flex; align-items: center; gap: 0.15rem; list-style: none; margin: 0; padding: 0.25rem; }
|
|
1809
|
+
.devbar .devbar-tool { display: inline-grid; place-items: center; width: 2.25rem; height: 2.25rem; border-radius: 7px; color: #dbe7ff;
|
|
1810
|
+
background: none; border: 0; cursor: pointer; list-style: none; padding: 0; }
|
|
1811
|
+
.devbar-tool::-webkit-details-marker { display: none; }
|
|
1812
|
+
.devbar .devbar-tool:hover, .devbar-menu[open] > .devbar-tool, .devbar-quick[aria-pressed="true"] { background: #2f3b4f; color: #fff; }
|
|
1813
|
+
.devbar-debug-menu.is-on > .devbar-tool { color: #ffd166; }
|
|
1814
|
+
.devbar a, .devbar-pop a { color: #9cc8ff; }
|
|
1815
|
+
.devbar a:focus-visible, .devbar button:focus-visible, .devbar select:focus-visible, .devbar summary:focus-visible, .devbar input:focus-visible { outline: 2px solid #9cc8ff; outline-offset: 2px; }
|
|
1816
|
+
.devbar-menu { position: relative; }
|
|
1817
|
+
.devbar-pop { position: absolute; bottom: calc(100% + 0.6rem); left: 50%; transform: translateX(-50%); min-width: 14rem; max-width: min(22rem, calc(100vw - 2rem));
|
|
1818
|
+
background: #1b2330; border-radius: 8px; box-shadow: 0 4px 16px rgb(0 0 0 / 30%); padding: 0.6rem 0.75rem; display: grid; gap: 0.5rem; }
|
|
1819
|
+
.devbar-debug { display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem; margin: 0; }
|
|
1820
|
+
.devbar-debug label { flex-basis: 100%; }
|
|
1659
1821
|
.devbar-debug select, .devbar-debug button { font: inherit; font-size: 0.8125rem; padding: 0.1rem 0.3rem; border-radius: 4px; border: 1px solid #5e6a7a; background: #2b3340; color: #fff; }
|
|
1660
1822
|
.devbar-debug button { cursor: pointer; }
|
|
1823
|
+
.devbar-dock { border: 0; margin: 0; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 0.25rem 0.75rem; }
|
|
1824
|
+
.devbar-dock legend { padding: 0; margin-bottom: 0.25rem; font-weight: 600; }
|
|
1825
|
+
.devbar-pop .devbar-facts { color: #fff; }
|
|
1826
|
+
/* docked at the top, or on the left or right edge (a column of icons) */
|
|
1827
|
+
.devbar[data-dock="top"] { bottom: auto; top: 0.5rem; }
|
|
1828
|
+
.devbar[data-dock="top"] .devbar-pop { bottom: auto; top: calc(100% + 0.6rem); }
|
|
1829
|
+
.devbar[data-dock="left"], .devbar[data-dock="right"] { left: 0.5rem; bottom: auto; top: 50%; transform: translateY(-50%); }
|
|
1830
|
+
.devbar[data-dock="right"] { left: auto; right: 0.5rem; }
|
|
1831
|
+
.devbar[data-dock="left"] .devbar-tools, .devbar[data-dock="right"] .devbar-tools { flex-direction: column; }
|
|
1832
|
+
.devbar[data-dock="left"] .devbar-pop { bottom: auto; top: 0; left: calc(100% + 0.6rem); transform: none; }
|
|
1833
|
+
.devbar[data-dock="right"] .devbar-pop { bottom: auto; top: 0; left: auto; right: calc(100% + 0.6rem); transform: none; }
|
|
1834
|
+
/* not used for a while: a slim tab at the edge; pointing at it or focusing it brings it back */
|
|
1835
|
+
.devbar.is-idle { opacity: 0.85; }
|
|
1836
|
+
.devbar.is-idle[data-dock="bottom"] { transform: translate(-50%, calc(100% - 6px)); }
|
|
1837
|
+
.devbar.is-idle[data-dock="top"] { transform: translate(-50%, calc(-100% + 6px)); }
|
|
1838
|
+
.devbar.is-idle[data-dock="left"] { transform: translate(calc(-100% + 6px), -50%); }
|
|
1839
|
+
.devbar.is-idle[data-dock="right"] { transform: translate(calc(100% - 6px), -50%); }
|
|
1840
|
+
.devbar.is-idle .devbar-tools { pointer-events: none; }
|
|
1841
|
+
@media (prefers-reduced-motion: reduce) { .devbar { transition: none; } }
|
|
1842
|
+
/* room for the bar: the menu and the page end above it */
|
|
1843
|
+
body:has(.devbar[data-dock="bottom"]) .t-main, body:has(.devbar[data-dock="bottom"]) .t-nav > ul { padding-bottom: 3.75rem; }
|
|
1844
|
+
body:has(.devbar[data-dock="top"]) .t-body { padding-top: 3.25rem; }
|
|
1845
|
+
body:has(.devbar[data-dock="left"]) .t-body { padding-left: 3.25rem; }
|
|
1846
|
+
body:has(.devbar[data-dock="right"]) .t-main { padding-right: 3.5rem; }
|
|
1661
1847
|
.devbar-page .t-main { max-width: 72rem; margin: 0 auto; padding: 1rem; }
|
|
1662
1848
|
.devbar-facts { display: grid; grid-template-columns: max-content 1fr; gap: 0.25rem 1rem; }
|
|
1663
1849
|
.devbar-facts dd { margin: 0; overflow-wrap: anywhere; }
|