trek 2.1.0 → 2.2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/Gemfile.lock +1 -1
- data/app/assets/icons/trek/audit.svg +1 -0
- data/app/assets/icons/trek/print.svg +1 -0
- data/app/components/trek/dashboard/analytics_component/analytics_component.html.slim +2 -0
- data/app/components/trek/dashboard/analytics_component.rb +1 -0
- data/app/components/trek/dashboard/chart_component/chart_component.css +192 -0
- data/app/components/trek/dashboard/chart_component/chart_component.html.slim +6 -0
- data/app/components/trek/dashboard/chart_component/chart_component.js +1 -0
- data/app/components/trek/dashboard/chart_component.rb +27 -0
- data/app/components/trek/dashboard/tile_component/tile_component.css +40 -0
- data/app/components/trek/dashboard/tile_component/tile_component.html.slim +14 -4
- data/app/components/trek/dashboard/tile_component.rb +6 -2
- data/app/components/trek/form/actions_component/actions_component.css +6 -7
- data/app/components/trek/form/content_editor_component/content_editor_component.html.slim +10 -12
- data/app/components/trek/form/content_editor_component/content_editor_component.js +4 -0
- data/app/components/trek/layout_component/layout_component.css +20 -0
- data/app/components/trek/layout_component/layout_component.html.slim +16 -0
- data/app/components/trek/layout_component/layout_component.js +35 -6
- data/app/formatters/prosemirror_to_html/global_id_to_links_formatter.rb +3 -1
- data/app/models/prosemirror.rb +5 -2
- data/app/views/trek/panels/images/_form.html.slim +1 -1
- data/app/views/trek/panels/images/create.turbo_stream.slim +3 -3
- data/app/views/trek/panels/images/new.html.slim +1 -1
- data/app/views/trek/panels/links/_form.html.slim +1 -1
- data/app/views/trek/panels/links/create.turbo_stream.slim +3 -3
- data/app/views/trek/panels/links/new.html.slim +1 -1
- data/app/views/trek/panels/prompts/_form.html.slim +1 -1
- data/app/views/trek/panels/prompts/create.turbo_stream.slim +3 -3
- data/app/views/trek/panels/prompts/new.html.slim +1 -1
- data/lib/trek/version.rb +1 -1
- data/package.json +1 -1
- metadata +7 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 76621e65ede62feb9ed4fd8aa029352bfbdda31c814a7e9679330597a631b2f6
|
|
4
|
+
data.tar.gz: a28bce934474a0d57069466281121658c75115eb9b9b1a3056eab9c6ee03ca5f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5653df741bf84cedce799a58c4f9d8c13d8a13226793f05d1f158b4971b0b08b1806463c82fa818526c8a0454d5b489f65cae207373c581bae074e1e3ae037bd
|
|
7
|
+
data.tar.gz: aad5fb5a6e0e9010c5b611ef2ba67e7ddf112d2b983c85684ce698d32083d1da82ac24469404f3377a131d3ef1be56ec369baa81bd9cd7e71b4560a916800e62
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [2.2.0] - 2026-08-28
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- `Trek::Dashboard::ChartComponent`, a dashboard card wrapping [Chartkick](https://chartkick.com) — pass `title`, `data`, a `type` (`:line_chart`, `:bar_chart`, …), optional `info`/`options`, and a `color` (default `:slate`); it renders `public_send(type, data, **options)` inside a coloured card matching the tiles. Chartkick is an **optional** dependency: the component only includes `Chartkick::Helper` when it is loaded, so Trek keeps working without it. `Trek::Dashboard::AnalyticsComponent` gained a `renders_many :charts` slot (alongside the existing `section`) so charts can be dropped straight into the dashboard with `a.with_chart(...)`. **Upgrade note:** to use `ChartComponent`, add `gem "chartkick"` to your app and `import "chartkick/chart.js"` in your admin JS bundle (Trek does not pull Chartkick in for you).
|
|
8
|
+
- `Trek::Dashboard::TileComponent` gained a `title` option (a large heading above the text, coloured per the tile's `color`) and a `wide` option (default `false`) that spans two tile columns. Its `href` is now optional: without one the tile renders as a plain `div` instead of a link, for read-only stat tiles.
|
|
9
|
+
- The layout gains a **stacked panel**: a second panel frame (`trek--layout-stacked-panel`) that opens on top of the primary one. The content editor's link/image/prompt inserters now open there, so an editor hosted _inside_ a panel (e.g. a Sectionable payload edited in a side panel) no longer loses its unsaved content when inserting a link — the primary panel stays put underneath and the inserted element lands back in the live editor. Closing the primary panel also closes the stacked one; _Annuler_ in the stacked panel closes only that one. The stacked panel is 1rem narrower than the primary panel (only while it stacks on an open one). **Upgrade note:** host apps that override the panel views (`app/views/<engine>/panels/{links,images,prompts}/*`) must retarget them to the `trek--layout-stacked-panel` frame and the `stackedPanelCloser` target, as Trek's own views now do.
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- Internal links inserted through the content editor (stored as `gid://` URLs) rendered as literal `gid://…` hrefs — or were dropped by the sanitizer — in formatted content: `Prosemirror#format_content` now resolves GlobalIDs to page paths before rendering, and the editor's Link extension accepts the `gid` protocol so reopening such a link shows the linked page instead of an empty field.
|
|
14
|
+
- `Trek::Form::ActionsComponent`: the sticky footer styling (sticky positioning, `--accent-1` background, `4rem` vertical padding) now only applies to the `default` aspect. It was set on the root rule, so the `seamless` aspect — used by `Trek::DialogComponent` — was also sticky and padded inside dialogs.
|
|
15
|
+
|
|
3
16
|
## [2.1.0] - 2026-08-25
|
|
4
17
|
|
|
5
18
|
### Added
|
data/Gemfile.lock
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 18a2 2 0 0 0-4 0"/><path d="m19 11-2.11-6.657a2 2 0 0 0-2.752-1.148l-1.276.61A2 2 0 0 1 12 4H8.5a2 2 0 0 0-1.925 1.456L5 11"/><path d="M2 11h20"/><circle cx="17" cy="18" r="3"/><circle cx="7" cy="18" r="3"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"/><path d="M6 9V3a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v6"/><rect x="6" y="14" width="12" height="8" rx="1"/></svg>
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
.root {
|
|
2
|
+
border: 0.1rem solid;
|
|
3
|
+
border-radius: 0.8rem;
|
|
4
|
+
font-weight: var(--semibold);
|
|
5
|
+
margin-bottom: 2rem;
|
|
6
|
+
max-width: 83.7rem;
|
|
7
|
+
padding: 2rem;
|
|
8
|
+
transition: background-color 0.2s ease-in-out, border-color 0.2s ease-in-out,
|
|
9
|
+
color 0.2s ease-in-out;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.root:last-child {
|
|
13
|
+
margin-bottom: 0;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.title {
|
|
17
|
+
color: var(--mint-12);
|
|
18
|
+
font-size: 1.6rem;
|
|
19
|
+
font-weight: var(--semibold);
|
|
20
|
+
margin: 0 0 0.5rem;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.data {
|
|
24
|
+
margin-bottom: 2rem;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.info {
|
|
28
|
+
color: var(--slate-11);
|
|
29
|
+
font-size: 1.4rem;
|
|
30
|
+
font-weight: var(--medium);
|
|
31
|
+
padding-bottom: 1.6rem;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.root.color-amber {
|
|
35
|
+
--icon-color: var(--amber-11);
|
|
36
|
+
|
|
37
|
+
background-color: var(--amber-2);
|
|
38
|
+
border-color: var(--amber-5);
|
|
39
|
+
color: var(--amber-12);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.root.color-amber:hover {
|
|
43
|
+
--icon-color: var(--amber-12);
|
|
44
|
+
|
|
45
|
+
background-color: var(--amber-3);
|
|
46
|
+
border-color: var(--amber-6);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.root.color-amber:active {
|
|
50
|
+
background-color: var(--amber-5);
|
|
51
|
+
border-color: var(--amber-7);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.root.color-lime {
|
|
55
|
+
--icon-color: var(--lime-11);
|
|
56
|
+
|
|
57
|
+
background-color: var(--lime-2);
|
|
58
|
+
border-color: var(--lime-5);
|
|
59
|
+
color: var(--lime-12);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.root.color-lime:hover {
|
|
63
|
+
--icon-color: var(--lime-12);
|
|
64
|
+
|
|
65
|
+
background-color: var(--lime-3);
|
|
66
|
+
border-color: var(--lime-6);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.root.color-lime:active {
|
|
70
|
+
background-color: var(--lime-5);
|
|
71
|
+
border-color: var(--lime-7);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.root.color-mint {
|
|
75
|
+
--icon-color: var(--mint-11);
|
|
76
|
+
|
|
77
|
+
background-color: var(--mint-2);
|
|
78
|
+
border-color: var(--mint-5);
|
|
79
|
+
color: var(--mint-12);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.root.color-mint:hover {
|
|
83
|
+
--icon-color: var(--mint-12);
|
|
84
|
+
|
|
85
|
+
background-color: var(--mint-3);
|
|
86
|
+
border-color: var(--mint-6);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.root.color-mint:active {
|
|
90
|
+
background-color: var(--mint-5);
|
|
91
|
+
border-color: var(--mint-7);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.root.color-purple {
|
|
95
|
+
--icon-color: var(--purple-11);
|
|
96
|
+
|
|
97
|
+
background-color: var(--purple-2);
|
|
98
|
+
border-color: var(--purple-5);
|
|
99
|
+
color: var(--purple-12);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.root.color-purple:hover {
|
|
103
|
+
--icon-color: var(--purple-12);
|
|
104
|
+
|
|
105
|
+
background-color: var(--purple-3);
|
|
106
|
+
border-color: var(--purple-6);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.root.color-purple:active {
|
|
110
|
+
background-color: var(--purple-5);
|
|
111
|
+
border-color: var(--purple-7);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.root.color-sky {
|
|
115
|
+
--icon-color: var(--sky-11);
|
|
116
|
+
|
|
117
|
+
background-color: var(--sky-2);
|
|
118
|
+
border-color: var(--sky-5);
|
|
119
|
+
color: var(--sky-12);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.root.color-sky:hover {
|
|
123
|
+
--icon-color: var(--sky-12);
|
|
124
|
+
|
|
125
|
+
background-color: var(--sky-3);
|
|
126
|
+
border-color: var(--sky-6);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.root.color-sky:active {
|
|
130
|
+
background-color: var(--sky-5);
|
|
131
|
+
border-color: var(--sky-7);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.root.color-slate {
|
|
135
|
+
--icon-color: var(--slate-11);
|
|
136
|
+
|
|
137
|
+
background-color: var(--slate-2);
|
|
138
|
+
border-color: var(--slate-5);
|
|
139
|
+
color: var(--slate-12);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.root.color-slate:hover {
|
|
143
|
+
--icon-color: var(--slate-12);
|
|
144
|
+
|
|
145
|
+
background-color: var(--slate-3);
|
|
146
|
+
border-color: var(--slate-6);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.root.color-slate:active {
|
|
150
|
+
background-color: var(--slate-5);
|
|
151
|
+
border-color: var(--slate-7);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.root.color-teal {
|
|
155
|
+
--icon-color: var(--teal-11);
|
|
156
|
+
|
|
157
|
+
background-color: var(--teal-2);
|
|
158
|
+
border-color: var(--teal-5);
|
|
159
|
+
color: var(--teal-12);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.root.color-teal:hover {
|
|
163
|
+
--icon-color: var(--teal-12);
|
|
164
|
+
|
|
165
|
+
background-color: var(--teal-3);
|
|
166
|
+
border-color: var(--teal-6);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.root.color-teal:active {
|
|
170
|
+
background-color: var(--teal-5);
|
|
171
|
+
border-color: var(--teal-7);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.root.color-violet {
|
|
175
|
+
--icon-color: var(--violet-11);
|
|
176
|
+
|
|
177
|
+
background-color: var(--violet-2);
|
|
178
|
+
border-color: var(--violet-5);
|
|
179
|
+
color: var(--violet-12);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.root.color-violet:hover {
|
|
183
|
+
--icon-color: var(--violet-12);
|
|
184
|
+
|
|
185
|
+
background-color: var(--violet-3);
|
|
186
|
+
border-color: var(--violet-6);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.root.color-violet:active {
|
|
190
|
+
background-color: var(--violet-5);
|
|
191
|
+
border-color: var(--violet-7);
|
|
192
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "./chart_component.css";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Trek
|
|
4
|
+
class Dashboard::ChartComponent < Trek::Component
|
|
5
|
+
# Chartkick is an optional dependency: host apps that use this component must
|
|
6
|
+
# add `gem "chartkick"` and import "chartkick/chart.js" in their JS bundle.
|
|
7
|
+
include Chartkick::Helper if defined?(Chartkick)
|
|
8
|
+
|
|
9
|
+
option :title
|
|
10
|
+
option :info, optional: true
|
|
11
|
+
option :data
|
|
12
|
+
option :type
|
|
13
|
+
option :options, optional: true, default: proc { {} }
|
|
14
|
+
option :color, default: proc { :slate }
|
|
15
|
+
|
|
16
|
+
def chart
|
|
17
|
+
public_send(type, data, **options)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def classes
|
|
21
|
+
class_names(
|
|
22
|
+
root_class,
|
|
23
|
+
class_for("color-#{color}")
|
|
24
|
+
)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -20,6 +20,14 @@
|
|
|
20
20
|
width: 20rem;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
.root.wide {
|
|
24
|
+
width: calc(40rem + 1.2rem);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.title {
|
|
28
|
+
font-size: 3.6rem;
|
|
29
|
+
}
|
|
30
|
+
|
|
23
31
|
.root:hover .icon {
|
|
24
32
|
transform: scale(1.125);
|
|
25
33
|
}
|
|
@@ -58,6 +66,10 @@
|
|
|
58
66
|
border-color: var(--amber-7);
|
|
59
67
|
}
|
|
60
68
|
|
|
69
|
+
.root.color-amber .title {
|
|
70
|
+
color: var(--amber-11);
|
|
71
|
+
}
|
|
72
|
+
|
|
61
73
|
.root.color-lime {
|
|
62
74
|
--icon-color: var(--lime-11);
|
|
63
75
|
|
|
@@ -78,6 +90,10 @@
|
|
|
78
90
|
border-color: var(--lime-7);
|
|
79
91
|
}
|
|
80
92
|
|
|
93
|
+
.root.color-lime .title {
|
|
94
|
+
color: var(--lime-11);
|
|
95
|
+
}
|
|
96
|
+
|
|
81
97
|
.root.color-mint {
|
|
82
98
|
--icon-color: var(--mint-11);
|
|
83
99
|
|
|
@@ -98,6 +114,10 @@
|
|
|
98
114
|
border-color: var(--mint-7);
|
|
99
115
|
}
|
|
100
116
|
|
|
117
|
+
.root.color-mint .title {
|
|
118
|
+
color: var(--mint-11);
|
|
119
|
+
}
|
|
120
|
+
|
|
101
121
|
.root.color-purple {
|
|
102
122
|
--icon-color: var(--purple-11);
|
|
103
123
|
|
|
@@ -118,6 +138,10 @@
|
|
|
118
138
|
border-color: var(--purple-7);
|
|
119
139
|
}
|
|
120
140
|
|
|
141
|
+
.root.color-purple .title {
|
|
142
|
+
color: var(--purple-11);
|
|
143
|
+
}
|
|
144
|
+
|
|
121
145
|
.root.color-sky {
|
|
122
146
|
--icon-color: var(--sky-11);
|
|
123
147
|
|
|
@@ -138,6 +162,10 @@
|
|
|
138
162
|
border-color: var(--sky-7);
|
|
139
163
|
}
|
|
140
164
|
|
|
165
|
+
.root.color-sky .title {
|
|
166
|
+
color: var(--sky-11);
|
|
167
|
+
}
|
|
168
|
+
|
|
141
169
|
.root.color-slate {
|
|
142
170
|
--icon-color: var(--slate-11);
|
|
143
171
|
|
|
@@ -158,6 +186,10 @@
|
|
|
158
186
|
border-color: var(--slate-7);
|
|
159
187
|
}
|
|
160
188
|
|
|
189
|
+
.root.color-slate .title {
|
|
190
|
+
color: var(--slate-11);
|
|
191
|
+
}
|
|
192
|
+
|
|
161
193
|
.root.color-teal {
|
|
162
194
|
--icon-color: var(--teal-11);
|
|
163
195
|
|
|
@@ -178,6 +210,10 @@
|
|
|
178
210
|
border-color: var(--teal-7);
|
|
179
211
|
}
|
|
180
212
|
|
|
213
|
+
.root.color-teal .title {
|
|
214
|
+
color: var(--teal-11);
|
|
215
|
+
}
|
|
216
|
+
|
|
181
217
|
.root.color-violet {
|
|
182
218
|
--icon-color: var(--violet-11);
|
|
183
219
|
|
|
@@ -197,3 +233,7 @@
|
|
|
197
233
|
background-color: var(--violet-5);
|
|
198
234
|
border-color: var(--violet-7);
|
|
199
235
|
}
|
|
236
|
+
|
|
237
|
+
.root.color-violet .title {
|
|
238
|
+
color: var(--violet-11);
|
|
239
|
+
}
|
|
@@ -1,4 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
- if href.present?
|
|
2
|
+
= link_to href, class: classes, rel: rel, target: target
|
|
3
|
+
- if title
|
|
4
|
+
span(class=class_for("title")) = title
|
|
5
|
+
- if icon
|
|
6
|
+
= render Trek::IconComponent.new(icon, classnames: class_for("icon"))
|
|
7
|
+
span(class=class_for("text")) = formatted_text
|
|
8
|
+
- else
|
|
9
|
+
div(class=classes)
|
|
10
|
+
- if title
|
|
11
|
+
span(class=class_for("title")) = title
|
|
12
|
+
- if icon
|
|
13
|
+
= render Trek::IconComponent.new(icon, classnames: class_for("icon"))
|
|
14
|
+
span(class=class_for("text")) = formatted_text
|
|
@@ -3,12 +3,15 @@
|
|
|
3
3
|
module Trek
|
|
4
4
|
class Dashboard::TileComponent < Trek::Component
|
|
5
5
|
option :color, default: proc { :slate }
|
|
6
|
-
option :href
|
|
6
|
+
option :href, optional: true
|
|
7
7
|
option :icon, optional: true
|
|
8
8
|
option :rel, optional: true
|
|
9
9
|
option :target, optional: true
|
|
10
10
|
option :text
|
|
11
|
+
option :title, optional: true
|
|
11
12
|
option :allowed_to, default: -> { true }
|
|
13
|
+
# Spans two tile columns (including the gap between them).
|
|
14
|
+
option :wide, default: proc { false }
|
|
12
15
|
|
|
13
16
|
def render?
|
|
14
17
|
allowed_to
|
|
@@ -17,7 +20,8 @@ module Trek
|
|
|
17
20
|
def classes
|
|
18
21
|
class_names(
|
|
19
22
|
root_class,
|
|
20
|
-
class_for("color-#{color}")
|
|
23
|
+
class_for("color-#{color}"),
|
|
24
|
+
class_for("wide") => wide
|
|
21
25
|
)
|
|
22
26
|
end
|
|
23
27
|
|
|
@@ -2,14 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
.root {
|
|
4
4
|
align-items: center;
|
|
5
|
-
background-color: var(--accent-1);
|
|
6
|
-
bottom: 0;
|
|
7
5
|
display: flex;
|
|
8
6
|
max-width: 120rem;
|
|
9
|
-
padding: 4rem 0;
|
|
10
|
-
position: sticky;
|
|
11
|
-
width: 100%;
|
|
12
|
-
z-index: 2;
|
|
13
7
|
}
|
|
14
8
|
|
|
15
9
|
.buttons {
|
|
@@ -36,9 +30,14 @@
|
|
|
36
30
|
|
|
37
31
|
/* aspect */
|
|
38
32
|
.root.aspect-default {
|
|
33
|
+
background-color: var(--accent-1);
|
|
39
34
|
border-top: 1px solid var(--slate-6);
|
|
35
|
+
bottom: 0;
|
|
40
36
|
margin-top: 3.2rem;
|
|
41
|
-
padding
|
|
37
|
+
padding: 3.2rem 0 4rem;
|
|
38
|
+
position: sticky;
|
|
39
|
+
width: 100%;
|
|
40
|
+
z-index: 2;
|
|
42
41
|
}
|
|
43
42
|
|
|
44
43
|
/* .root.aspect-seamless {
|
|
@@ -29,16 +29,14 @@ div(
|
|
|
29
29
|
/ data-action=stimulus_action("toggleCode")
|
|
30
30
|
/ ) code
|
|
31
31
|
|
|
32
|
-
/
|
|
32
|
+
/ The panel opening is handled by the hidden button's
|
|
33
|
+
openStackedPanelWhenLoaded action — a direct openPanel here would
|
|
34
|
+
pop the (possibly empty) primary panel alongside the stacked one.
|
|
33
35
|
button.link(
|
|
34
36
|
class=class_for("button")
|
|
35
37
|
type="button"
|
|
36
|
-
data-action=
|
|
37
|
-
stimulus_action("toggleLink"),
|
|
38
|
-
"trek--layout#openPanel",
|
|
39
|
-
].join(" ")
|
|
38
|
+
data-action=stimulus_action("toggleLink")
|
|
40
39
|
) = render Trek::IconComponent.new("trek/link", title: t(".link"))
|
|
41
|
-
/ slim-lint:enable ControlStatementSpacing
|
|
42
40
|
|
|
43
41
|
= link_to "",
|
|
44
42
|
new_link_path,
|
|
@@ -46,8 +44,8 @@ div(
|
|
|
46
44
|
hidden: true,
|
|
47
45
|
data: stimulus_target_hash("hiddenLinkButton").merge( \
|
|
48
46
|
'base-path': new_link_path,
|
|
49
|
-
action: "trek--layout#
|
|
50
|
-
'turbo-frame': "trek--layout-panel",
|
|
47
|
+
action: "trek--layout#openStackedPanelWhenLoaded",
|
|
48
|
+
'turbo-frame': "trek--layout-stacked-panel",
|
|
51
49
|
)
|
|
52
50
|
|
|
53
51
|
button(
|
|
@@ -239,8 +237,8 @@ div(
|
|
|
239
237
|
hidden: true,
|
|
240
238
|
data: stimulus_target_hash("hiddenPromptsButton").merge( \
|
|
241
239
|
'base-path': new_prompt_path,
|
|
242
|
-
action: "trek--layout#
|
|
243
|
-
'turbo-frame': "trek--layout-panel",
|
|
240
|
+
action: "trek--layout#openStackedPanelWhenLoaded",
|
|
241
|
+
'turbo-frame': "trek--layout-stacked-panel",
|
|
244
242
|
)
|
|
245
243
|
= link_to "",
|
|
246
244
|
new_image_path,
|
|
@@ -248,6 +246,6 @@ div(
|
|
|
248
246
|
hidden: true,
|
|
249
247
|
data: stimulus_target_hash("hiddenImageButton").merge( \
|
|
250
248
|
'base-path': new_image_path,
|
|
251
|
-
action: "trek--layout#
|
|
252
|
-
'turbo-frame': "trek--layout-panel",
|
|
249
|
+
action: "trek--layout#openStackedPanelWhenLoaded",
|
|
250
|
+
'turbo-frame': "trek--layout-stacked-panel",
|
|
253
251
|
)
|
|
@@ -41,6 +41,10 @@ export class Controller extends BaseController {
|
|
|
41
41
|
// }),
|
|
42
42
|
Link.configure({
|
|
43
43
|
openOnClick: false,
|
|
44
|
+
// Internal links are stored as GlobalIDs (resolved to URLs at render
|
|
45
|
+
// time); without this the gid:// scheme fails Link's URI validation
|
|
46
|
+
// and setLink silently does nothing.
|
|
47
|
+
protocols: ["gid"],
|
|
44
48
|
HTMLAttributes: {
|
|
45
49
|
"data-action": "trek--form--content-editor#selectLink",
|
|
46
50
|
target: null,
|
|
@@ -34,6 +34,18 @@
|
|
|
34
34
|
transform: translateX(0);
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
/* Stacked panel: overlays the primary panel. */
|
|
38
|
+
.panel-stacked {
|
|
39
|
+
box-shadow: 0 0 16px var(--slate-a8);
|
|
40
|
+
z-index: 3;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* Only when it actually stacks on an open primary panel, make it 1rem
|
|
44
|
+
narrower so a sliver of the panel underneath stays visible. */
|
|
45
|
+
.panel.open + .panel-stacked {
|
|
46
|
+
width: 41rem;
|
|
47
|
+
}
|
|
48
|
+
|
|
37
49
|
.panel-close {
|
|
38
50
|
--icon-size: 1.6rem;
|
|
39
51
|
|
|
@@ -65,4 +77,12 @@
|
|
|
65
77
|
.content {
|
|
66
78
|
margin: 6rem 3rem;
|
|
67
79
|
}
|
|
80
|
+
|
|
81
|
+
.panel {
|
|
82
|
+
width: 100vw;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.panel.open + .panel-stacked {
|
|
86
|
+
width: calc(100vw - 1rem);
|
|
87
|
+
}
|
|
68
88
|
}
|
|
@@ -18,3 +18,19 @@ div(
|
|
|
18
18
|
data-action=stimulus_action("closePanel")
|
|
19
19
|
)
|
|
20
20
|
= render(Trek::IconComponent.new("trek/close"))
|
|
21
|
+
/ Stacked panel: opens on top of the primary panel, so a panel-hosted form
|
|
22
|
+
(e.g. a content editor in a section panel) survives sub-panels like the
|
|
23
|
+
link/image/prompt inserters.
|
|
24
|
+
aside(
|
|
25
|
+
class=[class_for("panel"), class_for("panel-stacked")]
|
|
26
|
+
data=stimulus_target_hash("stackedPanel")
|
|
27
|
+
)
|
|
28
|
+
= turbo_frame_tag( \
|
|
29
|
+
"#{identifier}-stacked-panel",
|
|
30
|
+
data: stimulus_target_hash("stackedPanelFrame"),
|
|
31
|
+
)
|
|
32
|
+
button(
|
|
33
|
+
class=class_for("panel-close")
|
|
34
|
+
data-action=stimulus_action("closeStackedPanel")
|
|
35
|
+
)
|
|
36
|
+
= render(Trek::IconComponent.new("trek/close"))
|
|
@@ -5,7 +5,14 @@ import { useClickOutside } from "stimulus-use";
|
|
|
5
5
|
|
|
6
6
|
export class Controller extends BaseController {
|
|
7
7
|
static classes = ["open"];
|
|
8
|
-
static targets = [
|
|
8
|
+
static targets = [
|
|
9
|
+
"panel",
|
|
10
|
+
"panelFrame",
|
|
11
|
+
"panelCloser",
|
|
12
|
+
"stackedPanel",
|
|
13
|
+
"stackedPanelFrame",
|
|
14
|
+
"stackedPanelCloser",
|
|
15
|
+
];
|
|
9
16
|
|
|
10
17
|
connect() {
|
|
11
18
|
useClickOutside(this, { element: this.panelTarget });
|
|
@@ -17,31 +24,53 @@ export class Controller extends BaseController {
|
|
|
17
24
|
this.closePanel();
|
|
18
25
|
}
|
|
19
26
|
|
|
27
|
+
stackedPanelCloserTargetConnected() {
|
|
28
|
+
this.closeStackedPanel();
|
|
29
|
+
}
|
|
30
|
+
|
|
20
31
|
openPanelWhenLoaded() {
|
|
21
32
|
this.panelFrameTarget.loaded.then(() => this.openPanel());
|
|
22
33
|
}
|
|
23
34
|
|
|
35
|
+
openStackedPanelWhenLoaded() {
|
|
36
|
+
this.stackedPanelFrameTarget.loaded.then(() => this.openStackedPanel());
|
|
37
|
+
}
|
|
38
|
+
|
|
24
39
|
openPanel() {
|
|
25
40
|
this.panelTarget.classList.add(this.openClass);
|
|
26
41
|
}
|
|
27
42
|
|
|
43
|
+
openStackedPanel() {
|
|
44
|
+
this.stackedPanelTarget.classList.add(this.openClass);
|
|
45
|
+
}
|
|
46
|
+
|
|
28
47
|
closePanel() {
|
|
48
|
+
this.closeStackedPanel();
|
|
29
49
|
this.panelTarget.classList.remove(this.openClass);
|
|
30
|
-
this.emptyFrame();
|
|
50
|
+
this.emptyFrame(this.panelFrameTarget);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
closeStackedPanel() {
|
|
54
|
+
this.stackedPanelTarget.classList.remove(this.openClass);
|
|
55
|
+
this.emptyFrame(this.stackedPanelFrameTarget);
|
|
31
56
|
}
|
|
32
57
|
|
|
33
58
|
clickOutside(e) {
|
|
34
59
|
if (
|
|
35
60
|
e.target.dataset.action &&
|
|
36
|
-
e.target.dataset.action.includes("trek--layout#openPanel")
|
|
61
|
+
(e.target.dataset.action.includes("trek--layout#openPanel") ||
|
|
62
|
+
e.target.dataset.action.includes("trek--layout#openStackedPanel"))
|
|
37
63
|
)
|
|
38
64
|
return;
|
|
65
|
+
// Clicks inside the stacked panel are outside the primary panel element,
|
|
66
|
+
// but must not close anything.
|
|
67
|
+
if (this.stackedPanelTarget.contains(e.target)) return;
|
|
39
68
|
this.closePanel();
|
|
40
69
|
}
|
|
41
70
|
|
|
42
|
-
emptyFrame() {
|
|
43
|
-
while (
|
|
44
|
-
|
|
71
|
+
emptyFrame(frame) {
|
|
72
|
+
while (frame.firstChild) {
|
|
73
|
+
frame.removeChild(frame.firstChild);
|
|
45
74
|
}
|
|
46
75
|
}
|
|
47
76
|
}
|
|
@@ -2,7 +2,9 @@ module ProsemirrorToHtml
|
|
|
2
2
|
class GlobalIdToLinksFormatter
|
|
3
3
|
include Rails.application.routes.url_helpers
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
# The app segment allows hyphens and dots: GlobalID derives it from the
|
|
6
|
+
# Rails application name (e.g. "au-poste").
|
|
7
|
+
GLOBAL_ID_REGEX = %r{(gid://[\w.-]+/[\w:]+/[\w-]+)}
|
|
6
8
|
|
|
7
9
|
def initialize(str)
|
|
8
10
|
@str = str
|
data/app/models/prosemirror.rb
CHANGED
|
@@ -10,9 +10,12 @@ class Prosemirror
|
|
|
10
10
|
def format_content(parsed_content)
|
|
11
11
|
return if parsed_content.blank?
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
# GlobalIDs must be resolved to URLs before rendering: the renderer's
|
|
14
|
+
# sanitizer strips href attributes with unknown protocols, so a gid://
|
|
15
|
+
# link would lose its href entirely.
|
|
16
|
+
content = ProsemirrorToHtml::GlobalIdToLinksFormatter.new(parsed_content.to_json).to_s
|
|
17
|
+
content = renderer.render(JSON.parse(content))
|
|
14
18
|
content = ProsemirrorToHtml::RemoveEmptyParagraphsFormatter.new(content).to_s
|
|
15
|
-
content = ProsemirrorToHtml::GlobalIdToLinksFormatter.new(content).to_s
|
|
16
19
|
# rubocop:disable Rails/OutputSafety
|
|
17
20
|
content.html_safe
|
|
18
21
|
# rubocop:enable Rails/OutputSafety
|
|
@@ -24,7 +24,7 @@ h1.c-trek--layout-panel-title = t(".title")
|
|
|
24
24
|
= render Trek::Form::ActionsComponent.new do |c|
|
|
25
25
|
ruby:
|
|
26
26
|
c.with_button(
|
|
27
|
-
data: { action: "trek--layout#
|
|
27
|
+
data: { action: "trek--layout#closeStackedPanel" },
|
|
28
28
|
text: t("admin.actions.cancel"),
|
|
29
29
|
)
|
|
30
30
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
- if @object.valid?
|
|
2
|
-
= turbo_stream.append("trek--layout-panel")
|
|
3
|
-
div(data-trek--layout-target="
|
|
2
|
+
= turbo_stream.append("trek--layout-stacked-panel")
|
|
3
|
+
div(data-trek--layout-target="stackedPanelCloser")
|
|
4
4
|
|
|
5
5
|
= turbo_stream.append(@object.turbo_frame_id)
|
|
6
6
|
div(
|
|
@@ -15,5 +15,5 @@
|
|
|
15
15
|
text=@object.text
|
|
16
16
|
)
|
|
17
17
|
- else
|
|
18
|
-
= turbo_stream.update("trek--layout-panel")
|
|
18
|
+
= turbo_stream.update("trek--layout-stacked-panel")
|
|
19
19
|
= render "form"
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
= turbo_frame_tag("trek--layout-panel")
|
|
1
|
+
= turbo_frame_tag("trek--layout-stacked-panel")
|
|
2
2
|
= render "form"
|
|
@@ -28,7 +28,7 @@ h1.c-trek--layout-panel-title = t(".title")
|
|
|
28
28
|
= render Trek::Form::ActionsComponent.new do |c|
|
|
29
29
|
ruby:
|
|
30
30
|
c.with_button(
|
|
31
|
-
data: { action: "trek--layout#
|
|
31
|
+
data: { action: "trek--layout#closeStackedPanel" },
|
|
32
32
|
text: t("admin.actions.cancel"),
|
|
33
33
|
)
|
|
34
34
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
- if @object.valid?
|
|
2
|
-
= turbo_stream.append("trek--layout-panel")
|
|
3
|
-
div(data-trek--layout-target="
|
|
2
|
+
= turbo_stream.append("trek--layout-stacked-panel")
|
|
3
|
+
div(data-trek--layout-target="stackedPanelCloser")
|
|
4
4
|
|
|
5
5
|
= turbo_stream.append(@object.turbo_frame_id)
|
|
6
6
|
div(
|
|
@@ -8,5 +8,5 @@
|
|
|
8
8
|
data-params=@object.to_json
|
|
9
9
|
)
|
|
10
10
|
- else
|
|
11
|
-
= turbo_stream.update("trek--layout-panel")
|
|
11
|
+
= turbo_stream.update("trek--layout-stacked-panel")
|
|
12
12
|
= render "form"
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
= turbo_frame_tag("trek--layout-panel")
|
|
1
|
+
= turbo_frame_tag("trek--layout-stacked-panel")
|
|
2
2
|
= render "form"
|
|
@@ -26,7 +26,7 @@ h1.c-trek--layout-panel-title = t(".title")
|
|
|
26
26
|
= render Trek::Form::ActionsComponent.new do |c|
|
|
27
27
|
ruby:
|
|
28
28
|
c.with_button(
|
|
29
|
-
data: { action: "trek--layout#
|
|
29
|
+
data: { action: "trek--layout#closeStackedPanel" },
|
|
30
30
|
text: t("admin.actions.cancel"),
|
|
31
31
|
)
|
|
32
32
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
- if @object.valid?
|
|
2
|
-
= turbo_stream.append("trek--layout-panel")
|
|
3
|
-
div(data-trek--layout-target="
|
|
2
|
+
= turbo_stream.append("trek--layout-stacked-panel")
|
|
3
|
+
div(data-trek--layout-target="stackedPanelCloser")
|
|
4
4
|
|
|
5
5
|
= turbo_stream.append(@object.turbo_frame_id)
|
|
6
6
|
div(
|
|
@@ -14,5 +14,5 @@
|
|
|
14
14
|
title=@object.title
|
|
15
15
|
)
|
|
16
16
|
- else
|
|
17
|
-
= turbo_stream.update("trek--layout-panel")
|
|
17
|
+
= turbo_stream.update("trek--layout-stacked-panel")
|
|
18
18
|
= render "form"
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
= turbo_frame_tag("trek--layout-panel")
|
|
1
|
+
= turbo_frame_tag("trek--layout-stacked-panel")
|
|
2
2
|
= render "form"
|
data/lib/trek/version.rb
CHANGED
data/package.json
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: trek
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mohamed Bengrich
|
|
@@ -454,6 +454,7 @@ files:
|
|
|
454
454
|
- app/assets/icons/trek/add.svg
|
|
455
455
|
- app/assets/icons/trek/arrow-bar-left.svg
|
|
456
456
|
- app/assets/icons/trek/arrow-bar-right.svg
|
|
457
|
+
- app/assets/icons/trek/audit.svg
|
|
457
458
|
- app/assets/icons/trek/bold.svg
|
|
458
459
|
- app/assets/icons/trek/check.svg
|
|
459
460
|
- app/assets/icons/trek/chevron-double-left.svg
|
|
@@ -477,6 +478,7 @@ files:
|
|
|
477
478
|
- app/assets/icons/trek/logout.svg
|
|
478
479
|
- app/assets/icons/trek/paragraph.svg
|
|
479
480
|
- app/assets/icons/trek/pic.svg
|
|
481
|
+
- app/assets/icons/trek/print.svg
|
|
480
482
|
- app/assets/icons/trek/profile.svg
|
|
481
483
|
- app/assets/icons/trek/quotation.svg
|
|
482
484
|
- app/assets/icons/trek/rating.svg
|
|
@@ -510,6 +512,10 @@ files:
|
|
|
510
512
|
- app/components/trek/dashboard/analytics_component/analytics_component.css
|
|
511
513
|
- app/components/trek/dashboard/analytics_component/analytics_component.html.slim
|
|
512
514
|
- app/components/trek/dashboard/analytics_component/analytics_component.js
|
|
515
|
+
- app/components/trek/dashboard/chart_component.rb
|
|
516
|
+
- app/components/trek/dashboard/chart_component/chart_component.css
|
|
517
|
+
- app/components/trek/dashboard/chart_component/chart_component.html.slim
|
|
518
|
+
- app/components/trek/dashboard/chart_component/chart_component.js
|
|
513
519
|
- app/components/trek/dashboard/section_component.rb
|
|
514
520
|
- app/components/trek/dashboard/section_component/section_component.css
|
|
515
521
|
- app/components/trek/dashboard/section_component/section_component.html.slim
|