ember-tribe 2.6.7 → 2.6.9
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/README.md +544 -274
- package/blueprints/ember-tribe/files/app/components/storylang/arc-diagram.hbs +242 -0
- package/blueprints/ember-tribe/files/app/components/storylang/arc-diagram.js +432 -0
- package/blueprints/ember-tribe/files/app/components/storylang/index.hbs +457 -0
- package/blueprints/ember-tribe/files/app/components/storylang/index.js +177 -0
- package/blueprints/ember-tribe/files/app/components/storylang/node-detail.hbs +265 -0
- package/blueprints/ember-tribe/files/app/components/storylang/node-detail.js +91 -0
- package/blueprints/ember-tribe/files/app/index.html +2 -2
- package/blueprints/ember-tribe/files/app/templates/index.hbs +4 -4
- package/blueprints/ember-tribe/files/storylang +492 -75
- package/package.json +1 -1
- package/blueprints/ember-tribe/files/app/components/welcome-flame.hbs +0 -5
- package/blueprints/ember-tribe/files/public/assets/css/custom.css +0 -0
- package/blueprints/ember-tribe/files/public/assets/js/custom.js +0 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
{{! app/components/storylang/node-detail.hbs }}
|
|
2
|
+
|
|
3
|
+
<style>
|
|
4
|
+
/* ── NodeDetail component styles ── */
|
|
5
|
+
|
|
6
|
+
.sl-nd-root {
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-direction: column;
|
|
9
|
+
height: 100%;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/* ── Sticky header ── */
|
|
13
|
+
.sl-nd-head {
|
|
14
|
+
padding: 18px 20px 14px;
|
|
15
|
+
border-bottom: 1px solid #1e2530;
|
|
16
|
+
position: sticky;
|
|
17
|
+
top: 0;
|
|
18
|
+
background: #0d1117;
|
|
19
|
+
z-index: 2;
|
|
20
|
+
display: flex;
|
|
21
|
+
flex-direction: column;
|
|
22
|
+
gap: 0;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.sl-nd-head-row {
|
|
26
|
+
display: flex;
|
|
27
|
+
align-items: flex-start;
|
|
28
|
+
justify-content: space-between;
|
|
29
|
+
gap: 8px;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.sl-nd-badge {
|
|
33
|
+
display: inline-flex;
|
|
34
|
+
align-items: center;
|
|
35
|
+
gap: 5px;
|
|
36
|
+
padding: 2px 9px;
|
|
37
|
+
border-radius: 99px;
|
|
38
|
+
font-size: 0.68rem;
|
|
39
|
+
font-weight: 600;
|
|
40
|
+
letter-spacing: 0.06em;
|
|
41
|
+
text-transform: uppercase;
|
|
42
|
+
margin-bottom: 8px;
|
|
43
|
+
flex-shrink: 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.sl-nd-close {
|
|
47
|
+
background: none;
|
|
48
|
+
border: none;
|
|
49
|
+
cursor: pointer;
|
|
50
|
+
color: #3d4a58;
|
|
51
|
+
padding: 2px;
|
|
52
|
+
border-radius: 4px;
|
|
53
|
+
display: flex;
|
|
54
|
+
align-items: center;
|
|
55
|
+
flex-shrink: 0;
|
|
56
|
+
margin-top: 1px;
|
|
57
|
+
transition: color 0.12s;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.sl-nd-close:hover { color: #8895a7; }
|
|
61
|
+
|
|
62
|
+
.sl-nd-slug {
|
|
63
|
+
font-size: 0.88rem;
|
|
64
|
+
font-weight: 600;
|
|
65
|
+
color: #e8edf4;
|
|
66
|
+
word-break: break-all;
|
|
67
|
+
font-family: 'Berkeley Mono', 'Courier New', monospace;
|
|
68
|
+
line-height: 1.4;
|
|
69
|
+
flex: 1;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* ── Body ── */
|
|
73
|
+
.sl-nd-body {
|
|
74
|
+
padding: 14px 20px;
|
|
75
|
+
flex: 1;
|
|
76
|
+
overflow-y: auto;
|
|
77
|
+
scrollbar-width: thin;
|
|
78
|
+
scrollbar-color: #1e2530 transparent;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.sl-nd-body::-webkit-scrollbar { width: 4px; }
|
|
82
|
+
.sl-nd-body::-webkit-scrollbar-thumb { background: #1e2530; border-radius: 2px; }
|
|
83
|
+
|
|
84
|
+
/* ── Sections ── */
|
|
85
|
+
.sl-nd-section {
|
|
86
|
+
margin-bottom: 18px;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.sl-nd-section-title {
|
|
90
|
+
font-size: 0.65rem;
|
|
91
|
+
font-weight: 600;
|
|
92
|
+
letter-spacing: 0.1em;
|
|
93
|
+
text-transform: uppercase;
|
|
94
|
+
color: #3d4a58;
|
|
95
|
+
margin-bottom: 8px;
|
|
96
|
+
display: flex;
|
|
97
|
+
align-items: center;
|
|
98
|
+
gap: 6px;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.sl-nd-section-title::after {
|
|
102
|
+
content: '';
|
|
103
|
+
flex: 1;
|
|
104
|
+
height: 1px;
|
|
105
|
+
background: #1e2530;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* ── Tags ── */
|
|
109
|
+
.sl-nd-tags {
|
|
110
|
+
display: flex;
|
|
111
|
+
flex-wrap: wrap;
|
|
112
|
+
gap: 4px;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.sl-nd-tag {
|
|
116
|
+
padding: 2px 8px;
|
|
117
|
+
border-radius: 5px;
|
|
118
|
+
font-size: 0.68rem;
|
|
119
|
+
font-weight: 500;
|
|
120
|
+
background: #161b22;
|
|
121
|
+
border: 1px solid #1e2530;
|
|
122
|
+
color: #8895a7;
|
|
123
|
+
font-family: 'Berkeley Mono', 'Courier New', monospace;
|
|
124
|
+
line-height: 1.6;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.sl-nd-tag.linked {
|
|
128
|
+
cursor: pointer;
|
|
129
|
+
border-color: #2a3140;
|
|
130
|
+
transition: border-color 0.12s, color 0.12s;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.sl-nd-tag.linked:hover {
|
|
134
|
+
border-color: #4fc3f7;
|
|
135
|
+
color: #4fc3f7;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/* ── Connection rows ── */
|
|
139
|
+
.sl-nd-conn-row {
|
|
140
|
+
display: flex;
|
|
141
|
+
align-items: center;
|
|
142
|
+
gap: 6px;
|
|
143
|
+
margin-bottom: 5px;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.sl-nd-conn-arrow {
|
|
147
|
+
font-size: 0.65rem;
|
|
148
|
+
flex-shrink: 0;
|
|
149
|
+
width: 12px;
|
|
150
|
+
text-align: center;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.sl-nd-conn-kind {
|
|
154
|
+
font-size: 0.65rem;
|
|
155
|
+
color: #3d4a58;
|
|
156
|
+
flex-shrink: 0;
|
|
157
|
+
width: 56px;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.sl-nd-conn-slug {
|
|
161
|
+
font-family: 'Berkeley Mono', 'Courier New', monospace;
|
|
162
|
+
font-size: 0.68rem;
|
|
163
|
+
cursor: pointer;
|
|
164
|
+
padding: 1px 6px;
|
|
165
|
+
border-radius: 4px;
|
|
166
|
+
border: 1px solid #1e2530;
|
|
167
|
+
background: #161b22;
|
|
168
|
+
color: #8895a7;
|
|
169
|
+
transition: border-color 0.12s, color 0.12s;
|
|
170
|
+
word-break: break-all;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.sl-nd-conn-slug:hover {
|
|
174
|
+
border-color: #4fc3f7;
|
|
175
|
+
color: #4fc3f7;
|
|
176
|
+
}
|
|
177
|
+
</style>
|
|
178
|
+
|
|
179
|
+
{{#if @node}}
|
|
180
|
+
<div class="sl-nd-root">
|
|
181
|
+
|
|
182
|
+
{{! ── Header ── }}
|
|
183
|
+
<div class="sl-nd-head">
|
|
184
|
+
|
|
185
|
+
<div class="sl-nd-head-row">
|
|
186
|
+
<div>
|
|
187
|
+
<div
|
|
188
|
+
class="sl-nd-badge"
|
|
189
|
+
style="background:{{this.typeColor}}22; color:{{this.typeColor}}; border:1px solid {{this.typeColor}}44;"
|
|
190
|
+
>
|
|
191
|
+
<svg width="6" height="6">
|
|
192
|
+
<circle cx="3" cy="3" r="3" fill={{this.typeColor}} />
|
|
193
|
+
</svg>
|
|
194
|
+
{{@node.type}}
|
|
195
|
+
</div>
|
|
196
|
+
<div class="sl-nd-slug">{{@node.slug}}</div>
|
|
197
|
+
</div>
|
|
198
|
+
|
|
199
|
+
<button class="sl-nd-close" type="button" {{on "click" this.close}} title="Deselect">
|
|
200
|
+
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="2">
|
|
201
|
+
<path d="M2 2l10 10M12 2L2 12"/>
|
|
202
|
+
</svg>
|
|
203
|
+
</button>
|
|
204
|
+
</div>
|
|
205
|
+
|
|
206
|
+
</div>
|
|
207
|
+
|
|
208
|
+
{{! ── Body ── }}
|
|
209
|
+
<div class="sl-nd-body">
|
|
210
|
+
|
|
211
|
+
{{! ── Connections ── }}
|
|
212
|
+
{{#if this.hasConnections}}
|
|
213
|
+
<div class="sl-nd-section">
|
|
214
|
+
<div class="sl-nd-section-title">Connections</div>
|
|
215
|
+
|
|
216
|
+
{{#each this.outgoingEdges as |edge|}}
|
|
217
|
+
<div class="sl-nd-conn-row">
|
|
218
|
+
<span class="sl-nd-conn-arrow" style="color:{{edge.arrowColor}}">→</span>
|
|
219
|
+
<span class="sl-nd-conn-kind">{{edge.kind}}</span>
|
|
220
|
+
<span
|
|
221
|
+
class="sl-nd-conn-slug"
|
|
222
|
+
role="button"
|
|
223
|
+
{{on "click" (fn this.navigateTo edge.slug)}}
|
|
224
|
+
>{{edge.slug}}</span>
|
|
225
|
+
</div>
|
|
226
|
+
{{/each}}
|
|
227
|
+
|
|
228
|
+
{{#each this.incomingEdges as |edge|}}
|
|
229
|
+
<div class="sl-nd-conn-row">
|
|
230
|
+
<span class="sl-nd-conn-arrow" style="color:{{edge.arrowColor}}">←</span>
|
|
231
|
+
<span class="sl-nd-conn-kind">{{edge.kind}}</span>
|
|
232
|
+
<span
|
|
233
|
+
class="sl-nd-conn-slug"
|
|
234
|
+
role="button"
|
|
235
|
+
{{on "click" (fn this.navigateTo edge.slug)}}
|
|
236
|
+
>{{edge.slug}}</span>
|
|
237
|
+
</div>
|
|
238
|
+
{{/each}}
|
|
239
|
+
</div>
|
|
240
|
+
{{/if}}
|
|
241
|
+
|
|
242
|
+
{{! ── Property sections ── }}
|
|
243
|
+
{{#each this.sections as |section|}}
|
|
244
|
+
<div class="sl-nd-section">
|
|
245
|
+
<div class="sl-nd-section-title">{{section.title}}</div>
|
|
246
|
+
<div class="sl-nd-tags">
|
|
247
|
+
{{#each section.items as |item|}}
|
|
248
|
+
{{#if item.linked}}
|
|
249
|
+
<span
|
|
250
|
+
class="sl-nd-tag linked"
|
|
251
|
+
role="button"
|
|
252
|
+
{{on "click" (fn this.navigateTo item.label)}}
|
|
253
|
+
>{{item.label}}</span>
|
|
254
|
+
{{else}}
|
|
255
|
+
<span class="sl-nd-tag">{{item.label}}</span>
|
|
256
|
+
{{/if}}
|
|
257
|
+
{{/each}}
|
|
258
|
+
</div>
|
|
259
|
+
</div>
|
|
260
|
+
{{/each}}
|
|
261
|
+
|
|
262
|
+
</div>
|
|
263
|
+
|
|
264
|
+
</div>
|
|
265
|
+
{{/if}}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import Component from '@glimmer/component';
|
|
2
|
+
import { action } from '@ember/object';
|
|
3
|
+
import { TYPE_COLOR, EDGE_COLOR } from './arc-diagram';
|
|
4
|
+
|
|
5
|
+
// ─── Component ──────────────────────────────────────────────────────────────
|
|
6
|
+
//
|
|
7
|
+
// Args:
|
|
8
|
+
// @node – { id, slug, type, data }
|
|
9
|
+
// @edges – edges already filtered to only those touching @node
|
|
10
|
+
// [{ source, target, kind }]
|
|
11
|
+
// @allNodes – full node list (used for navigate-on-click)
|
|
12
|
+
// @onNavigate – (node) => void navigate to a connected node
|
|
13
|
+
// @onClose – () => void deselect / clear
|
|
14
|
+
//
|
|
15
|
+
export default class StorylangNodeDetailComponent extends Component {
|
|
16
|
+
|
|
17
|
+
// ── Colour for the current node's type ───────────────────────────────────
|
|
18
|
+
|
|
19
|
+
get typeColor() {
|
|
20
|
+
return TYPE_COLOR[this.args.node?.type] ?? '#8895a7';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// ── Outgoing / incoming edge rows ─────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
get outgoingEdges() {
|
|
26
|
+
const slug = this.args.node?.slug;
|
|
27
|
+
return (this.args.edges ?? [])
|
|
28
|
+
.filter(e => e.source === slug)
|
|
29
|
+
.map(e => ({
|
|
30
|
+
slug: e.target,
|
|
31
|
+
kind: e.kind,
|
|
32
|
+
arrowColor: EDGE_COLOR[e.kind] ?? '#8895a7',
|
|
33
|
+
direction: 'out',
|
|
34
|
+
}));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
get incomingEdges() {
|
|
38
|
+
const slug = this.args.node?.slug;
|
|
39
|
+
return (this.args.edges ?? [])
|
|
40
|
+
.filter(e => e.target === slug)
|
|
41
|
+
.map(e => ({
|
|
42
|
+
slug: e.source,
|
|
43
|
+
kind: e.kind,
|
|
44
|
+
arrowColor: EDGE_COLOR[e.kind] ?? '#8895a7',
|
|
45
|
+
direction: 'in',
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
get hasConnections() {
|
|
50
|
+
return this.outgoingEdges.length > 0 || this.incomingEdges.length > 0;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ── Data sections for the properties list ────────────────────────────────
|
|
54
|
+
//
|
|
55
|
+
// Each section: { title, items: [{ label, linked }] }
|
|
56
|
+
|
|
57
|
+
get sections() {
|
|
58
|
+
const d = this.args.node?.data;
|
|
59
|
+
if (!d) return [];
|
|
60
|
+
|
|
61
|
+
const toItems = (arr, linked = false) =>
|
|
62
|
+
(arr ?? []).map(a => ({
|
|
63
|
+
label: typeof a === 'string' ? a : Object.keys(a)[0],
|
|
64
|
+
linked,
|
|
65
|
+
}));
|
|
66
|
+
|
|
67
|
+
return [
|
|
68
|
+
{ title: 'Tracked Vars', items: toItems(d.tracked_vars) },
|
|
69
|
+
{ title: 'Inherited Args', items: toItems(d.inherited_args) },
|
|
70
|
+
{ title: 'Getters', items: toItems(d.getters) },
|
|
71
|
+
{ title: 'Actions', items: toItems(d.actions) },
|
|
72
|
+
{ title: 'Functions', items: toItems(d.functions) },
|
|
73
|
+
{ title: 'Services', items: toItems(d.services, true) },
|
|
74
|
+
{ title: 'Components', items: toItems(d.components, true) },
|
|
75
|
+
{ title: 'Modifiers', items: toItems(d.modifiers) },
|
|
76
|
+
].filter(s => s.items.length > 0);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ── Actions ───────────────────────────────────────────────────────────────
|
|
80
|
+
|
|
81
|
+
@action
|
|
82
|
+
navigateTo(slug) {
|
|
83
|
+
const target = (this.args.allNodes ?? []).find(n => n.slug === slug);
|
|
84
|
+
if (target) this.args.onNavigate?.(target);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@action
|
|
88
|
+
close() {
|
|
89
|
+
this.args.onClose?.();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
/>
|
|
20
20
|
<link
|
|
21
21
|
rel="stylesheet"
|
|
22
|
-
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/
|
|
22
|
+
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css"
|
|
23
23
|
/>
|
|
24
24
|
|
|
25
25
|
{{content-for "head-footer"}}
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
|
|
44
44
|
{{content-for "body"}}
|
|
45
45
|
|
|
46
|
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/
|
|
46
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/js/all.min.js"></script>
|
|
47
47
|
<script src="{{rootURL}}assets/vendor.js"></script>
|
|
48
48
|
<script src="{{rootURL}}assets/<%= dasherizedPackageName %>.js"></script>
|
|
49
49
|
|