@yuneta/gobj-ui 7.23.137 → 7.23.139
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/dist/gobj-ui.cjs.js +136 -17
- package/dist/gobj-ui.es.js +136 -17
- package/package.json +1 -1
- package/src/c_yui_treedb_topics.css +25 -0
- package/src/c_yui_treedb_topics.js +120 -19
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -21798,7 +21798,7 @@ var attrs_table$6 = [
|
|
|
21798
21798
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "tabs_style", 0, "is-toggle is-fullwidth", "Bulma tab styling"),
|
|
21799
21799
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "with_cards_landing", 0, false, "Land on a grid of topic cards (list->detail): a card opens its table, with the tabs bar + a back-to-grid button. Off = tabs only (legacy)."),
|
|
21800
21800
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "readonly", 0, false, "The whole treedb is read-only: every topic opens without its write affordances and the write events are refused. Set it when this yuno is not the MASTER of the treedb's tranger -- only the master can write, and the yuno answers 'READ-ONLY' to a write since SDK 7.13.0 (ask `treedb-info`)"),
|
|
21801
|
-
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_JSON, "card_action_routes", 0, null, "
|
|
21801
|
+
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_JSON, "card_action_routes", 0, null, "Hash-route templates {info, table, graph} with a {topic} placeholder (host-supplied, route-agnostic). Present ⇒ cards show the info and table icons, and `graph` without its `/{topic}` is the toolbar's graph button (the card has no graph icon: its topic segment is a focus); absent ⇒ a single card that opens the table."),
|
|
21802
21802
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_JSON, "landing_routes", 0, null, "Host-supplied hashes for the two landing sub-views {cards, schema}; the toggle navigates to them so the landing is URL-addressable (ROUTING.md). Absent ⇒ toggle flips in-view only (legacy)."),
|
|
21803
21803
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "base_route", 0, "", "This view's base route (host-supplied); used to declare its sub-routes (topics / info / schema) to the site map (ROUTING.md contributor)."),
|
|
21804
21804
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "source_url", 0, "", "The backend this view browses (host-supplied, typically the wss url of the connection), shown in the toolbar. A tab label names the TREEDB, and the same treedb name lives on more than one node, so the node has to be readable somewhere -- and a tab is too narrow to carry a url. Empty ⇒ nothing is shown."),
|
|
@@ -21908,6 +21908,31 @@ function cmd_get_topic_data$1(gobj, cmd, kw, src) {
|
|
|
21908
21908
|
************************************************************/
|
|
21909
21909
|
function build_ui$6(gobj) {
|
|
21910
21910
|
let source_url = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "source_url") || "";
|
|
21911
|
+
let routes = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "card_action_routes");
|
|
21912
|
+
let graph_tpl = (0, _yuneta_gobj_js.is_object)(routes) && typeof routes.graph === "string" ? routes.graph : "";
|
|
21913
|
+
let graph_href = /\/\{topic\}$/.test(graph_tpl) ? graph_tpl.replace(/\/\{topic\}$/, "") : "";
|
|
21914
|
+
let graph_items = [];
|
|
21915
|
+
if (graph_href) graph_items.push([
|
|
21916
|
+
"a",
|
|
21917
|
+
{
|
|
21918
|
+
class: "button TREEDB_GRAPH_BTN",
|
|
21919
|
+
href: graph_href,
|
|
21920
|
+
style: "margin-left:auto;",
|
|
21921
|
+
title: (0, i18next.t)("graph"),
|
|
21922
|
+
"aria-label": (0, i18next.t)("graph"),
|
|
21923
|
+
"data-i18n-title": "graph",
|
|
21924
|
+
"data-i18n-aria-label": "graph"
|
|
21925
|
+
},
|
|
21926
|
+
[[
|
|
21927
|
+
"span",
|
|
21928
|
+
{ class: "icon" },
|
|
21929
|
+
[yui_toolbar_icon("yi-hexagon-nodes")]
|
|
21930
|
+
], [
|
|
21931
|
+
"span",
|
|
21932
|
+
{ i18n: "graph" },
|
|
21933
|
+
"graph"
|
|
21934
|
+
]]
|
|
21935
|
+
]);
|
|
21911
21936
|
let $container = (0, _yuneta_gobj_js.createElement2)([
|
|
21912
21937
|
"div",
|
|
21913
21938
|
{
|
|
@@ -21988,11 +22013,12 @@ function build_ui$6(gobj) {
|
|
|
21988
22013
|
source_url
|
|
21989
22014
|
]]
|
|
21990
22015
|
],
|
|
22016
|
+
...graph_items,
|
|
21991
22017
|
[
|
|
21992
22018
|
"button",
|
|
21993
22019
|
{
|
|
21994
22020
|
class: "button TREEDB_JSON_BTN",
|
|
21995
|
-
style: "margin-left:auto;",
|
|
22021
|
+
style: graph_href ? "" : "margin-left:auto;",
|
|
21996
22022
|
title: (0, i18next.t)("raw json"),
|
|
21997
22023
|
"aria-label": (0, i18next.t)("raw json"),
|
|
21998
22024
|
"data-i18n-title": "raw json",
|
|
@@ -22195,13 +22221,103 @@ function card_action_anchor(logical_class, icon, i18n_key, href) {
|
|
|
22195
22221
|
];
|
|
22196
22222
|
}
|
|
22197
22223
|
/************************************************************
|
|
22224
|
+
* What a topic card says about its topic, from its desc alone
|
|
22225
|
+
* (no request): its version and how many columns it has, the
|
|
22226
|
+
* topics it hangs FROM (its fkeys) and the ones that hang from
|
|
22227
|
+
* it (its hooks). The names are DATA and are not translated;
|
|
22228
|
+
* each label carries its key. Lists are cut with an ellipsis,
|
|
22229
|
+
* whole in the title.
|
|
22230
|
+
************************************************************/
|
|
22231
|
+
function topic_card_meta(desc) {
|
|
22232
|
+
if (!(0, _yuneta_gobj_js.is_object)(desc)) return [];
|
|
22233
|
+
let cols = (0, _yuneta_gobj_js.is_array)(desc.cols) ? desc.cols : [];
|
|
22234
|
+
let n_cols = 0;
|
|
22235
|
+
let parents = [];
|
|
22236
|
+
let children = [];
|
|
22237
|
+
for (let col of cols) {
|
|
22238
|
+
if (!col || !col.id || col.id.charAt(0) === "_") continue;
|
|
22239
|
+
n_cols++;
|
|
22240
|
+
if ((0, _yuneta_gobj_js.is_object)(col.fkey)) {
|
|
22241
|
+
for (let t_name of Object.keys(col.fkey)) if (!parents.includes(t_name)) parents.push(t_name);
|
|
22242
|
+
}
|
|
22243
|
+
if ((0, _yuneta_gobj_js.is_object)(col.hook)) {
|
|
22244
|
+
for (let t_name of Object.keys(col.hook)) if (!children.includes(t_name)) children.push(t_name);
|
|
22245
|
+
}
|
|
22246
|
+
}
|
|
22247
|
+
let meta = [];
|
|
22248
|
+
let head = [];
|
|
22249
|
+
if (desc.topic_version !== void 0 && desc.topic_version !== null && desc.topic_version !== "") head.push([
|
|
22250
|
+
"span",
|
|
22251
|
+
{
|
|
22252
|
+
class: "TREEDB_TOPIC_CARD_VERSION",
|
|
22253
|
+
title: (0, i18next.t)("version"),
|
|
22254
|
+
"data-i18n-title": "version"
|
|
22255
|
+
},
|
|
22256
|
+
`v${desc.topic_version}`
|
|
22257
|
+
]);
|
|
22258
|
+
head.push([
|
|
22259
|
+
"span",
|
|
22260
|
+
{ class: "TREEDB_TOPIC_CARD_COLS" },
|
|
22261
|
+
[[
|
|
22262
|
+
"span",
|
|
22263
|
+
{},
|
|
22264
|
+
`${n_cols}`
|
|
22265
|
+
], [
|
|
22266
|
+
"span",
|
|
22267
|
+
{ i18n: "columns" },
|
|
22268
|
+
"columns"
|
|
22269
|
+
]]
|
|
22270
|
+
]);
|
|
22271
|
+
meta.push([
|
|
22272
|
+
"div",
|
|
22273
|
+
{ class: "TREEDB_TOPIC_CARD_META" },
|
|
22274
|
+
head
|
|
22275
|
+
]);
|
|
22276
|
+
let relation = (cls, key, arrow, names) => {
|
|
22277
|
+
let list = names.join(", ");
|
|
22278
|
+
return [
|
|
22279
|
+
"div",
|
|
22280
|
+
{
|
|
22281
|
+
class: `TREEDB_TOPIC_CARD_REL ${cls}`,
|
|
22282
|
+
title: list
|
|
22283
|
+
},
|
|
22284
|
+
[
|
|
22285
|
+
[
|
|
22286
|
+
"span",
|
|
22287
|
+
{
|
|
22288
|
+
class: "TREEDB_TOPIC_CARD_REL_ARROW",
|
|
22289
|
+
"aria-hidden": "true"
|
|
22290
|
+
},
|
|
22291
|
+
arrow
|
|
22292
|
+
],
|
|
22293
|
+
[
|
|
22294
|
+
"span",
|
|
22295
|
+
{
|
|
22296
|
+
class: "TREEDB_TOPIC_CARD_REL_LABEL",
|
|
22297
|
+
i18n: key
|
|
22298
|
+
},
|
|
22299
|
+
key
|
|
22300
|
+
],
|
|
22301
|
+
[
|
|
22302
|
+
"span",
|
|
22303
|
+
{ class: "TREEDB_TOPIC_CARD_REL_LIST" },
|
|
22304
|
+
list
|
|
22305
|
+
]
|
|
22306
|
+
]
|
|
22307
|
+
];
|
|
22308
|
+
};
|
|
22309
|
+
if (parents.length) meta.push(relation("TREEDB_TOPIC_CARD_PARENTS", "parents", "↑", parents));
|
|
22310
|
+
if (children.length) meta.push(relation("TREEDB_TOPIC_CARD_CHILDREN", "children", "↓", children));
|
|
22311
|
+
return meta;
|
|
22312
|
+
}
|
|
22313
|
+
/************************************************************
|
|
22198
22314
|
* Add one topic card to the cards-landing grid (list->detail).
|
|
22199
22315
|
* With `card_action_routes` (host-supplied templates) the card
|
|
22200
22316
|
* shows three hash-routed icons — info / table / graph. Without,
|
|
22201
22317
|
* it falls back to a single card that opens the table (same id
|
|
22202
22318
|
* contract as the tab, `<gobj>?<topic>`).
|
|
22203
22319
|
************************************************************/
|
|
22204
|
-
function add_topic_card(gobj, id, text, icon) {
|
|
22320
|
+
function add_topic_card(gobj, id, text, icon, desc) {
|
|
22205
22321
|
let $grid = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container").querySelector(".TREEDB_TOPICS_LANDING .yui-nav-cards");
|
|
22206
22322
|
if (!$grid) return;
|
|
22207
22323
|
let routes = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "card_action_routes");
|
|
@@ -22244,25 +22360,28 @@ function add_topic_card(gobj, id, text, icon) {
|
|
|
22244
22360
|
let actions = [];
|
|
22245
22361
|
if (routes.info) actions.push(card_action_anchor("TREEDB_CARD_INFO", "yi-circle-info", "info", fill(routes.info)));
|
|
22246
22362
|
if (routes.table) actions.push(card_action_anchor("TREEDB_CARD_TABLE", "yi-table", "table", fill(routes.table)));
|
|
22247
|
-
if (routes.graph) actions.push(card_action_anchor("TREEDB_CARD_GRAPH", "yi-hexagon-nodes", "graph", fill(routes.graph)));
|
|
22248
22363
|
let $card = (0, _yuneta_gobj_js.createElement2)([
|
|
22249
22364
|
"div",
|
|
22250
22365
|
{
|
|
22251
22366
|
class: "TREEDB_TOPIC_CARD",
|
|
22252
22367
|
"data-topic": topic
|
|
22253
22368
|
},
|
|
22254
|
-
[
|
|
22255
|
-
|
|
22256
|
-
|
|
22257
|
-
|
|
22258
|
-
|
|
22259
|
-
|
|
22260
|
-
|
|
22261
|
-
|
|
22262
|
-
|
|
22263
|
-
|
|
22264
|
-
|
|
22265
|
-
|
|
22369
|
+
[
|
|
22370
|
+
[
|
|
22371
|
+
"span",
|
|
22372
|
+
{
|
|
22373
|
+
class: "TREEDB_TOPIC_CARD_NAME",
|
|
22374
|
+
i18n: text
|
|
22375
|
+
},
|
|
22376
|
+
text
|
|
22377
|
+
],
|
|
22378
|
+
...topic_card_meta(desc),
|
|
22379
|
+
[
|
|
22380
|
+
"div",
|
|
22381
|
+
{ class: "TREEDB_TOPIC_CARD_ACTIONS" },
|
|
22382
|
+
actions
|
|
22383
|
+
]
|
|
22384
|
+
]
|
|
22266
22385
|
]);
|
|
22267
22386
|
if (gobj.priv._selected_card_topic === topic) $card.classList.add("is-selected");
|
|
22268
22387
|
$card.addEventListener("click", function() {
|
|
@@ -22615,7 +22734,7 @@ function process_treedb_descs$1(gobj) {
|
|
|
22615
22734
|
let id = `${(0, _yuneta_gobj_js.gobj_name)(gobj)}?${desc.topic_name}`;
|
|
22616
22735
|
let gobj_topic_form = (0, _yuneta_gobj_js.gobj_create_service)(id, "C_YUI_TREEDB_TOPIC_WITH_FORM", kw_topic_form, gobj);
|
|
22617
22736
|
add_tab(gobj, gobj_topic_form, id, key, "yi-table");
|
|
22618
|
-
add_topic_card(gobj, id, key, "yi-table");
|
|
22737
|
+
add_topic_card(gobj, id, key, "yi-table", desc);
|
|
22619
22738
|
(0, _yuneta_gobj_js.gobj_start)(gobj_topic_form);
|
|
22620
22739
|
}
|
|
22621
22740
|
let href = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "last_selection");
|
package/dist/gobj-ui.es.js
CHANGED
|
@@ -21793,7 +21793,7 @@ var attrs_table$6 = [
|
|
|
21793
21793
|
SDATA(data_type_t.DTP_STRING, "tabs_style", 0, "is-toggle is-fullwidth", "Bulma tab styling"),
|
|
21794
21794
|
SDATA(data_type_t.DTP_BOOLEAN, "with_cards_landing", 0, false, "Land on a grid of topic cards (list->detail): a card opens its table, with the tabs bar + a back-to-grid button. Off = tabs only (legacy)."),
|
|
21795
21795
|
SDATA(data_type_t.DTP_BOOLEAN, "readonly", 0, false, "The whole treedb is read-only: every topic opens without its write affordances and the write events are refused. Set it when this yuno is not the MASTER of the treedb's tranger -- only the master can write, and the yuno answers 'READ-ONLY' to a write since SDK 7.13.0 (ask `treedb-info`)"),
|
|
21796
|
-
SDATA(data_type_t.DTP_JSON, "card_action_routes", 0, null, "
|
|
21796
|
+
SDATA(data_type_t.DTP_JSON, "card_action_routes", 0, null, "Hash-route templates {info, table, graph} with a {topic} placeholder (host-supplied, route-agnostic). Present ⇒ cards show the info and table icons, and `graph` without its `/{topic}` is the toolbar's graph button (the card has no graph icon: its topic segment is a focus); absent ⇒ a single card that opens the table."),
|
|
21797
21797
|
SDATA(data_type_t.DTP_JSON, "landing_routes", 0, null, "Host-supplied hashes for the two landing sub-views {cards, schema}; the toggle navigates to them so the landing is URL-addressable (ROUTING.md). Absent ⇒ toggle flips in-view only (legacy)."),
|
|
21798
21798
|
SDATA(data_type_t.DTP_STRING, "base_route", 0, "", "This view's base route (host-supplied); used to declare its sub-routes (topics / info / schema) to the site map (ROUTING.md contributor)."),
|
|
21799
21799
|
SDATA(data_type_t.DTP_STRING, "source_url", 0, "", "The backend this view browses (host-supplied, typically the wss url of the connection), shown in the toolbar. A tab label names the TREEDB, and the same treedb name lives on more than one node, so the node has to be readable somewhere -- and a tab is too narrow to carry a url. Empty ⇒ nothing is shown."),
|
|
@@ -21903,6 +21903,31 @@ function cmd_get_topic_data$1(gobj, cmd, kw, src) {
|
|
|
21903
21903
|
************************************************************/
|
|
21904
21904
|
function build_ui$6(gobj) {
|
|
21905
21905
|
let source_url = gobj_read_str_attr(gobj, "source_url") || "";
|
|
21906
|
+
let routes = gobj_read_attr(gobj, "card_action_routes");
|
|
21907
|
+
let graph_tpl = is_object(routes) && typeof routes.graph === "string" ? routes.graph : "";
|
|
21908
|
+
let graph_href = /\/\{topic\}$/.test(graph_tpl) ? graph_tpl.replace(/\/\{topic\}$/, "") : "";
|
|
21909
|
+
let graph_items = [];
|
|
21910
|
+
if (graph_href) graph_items.push([
|
|
21911
|
+
"a",
|
|
21912
|
+
{
|
|
21913
|
+
class: "button TREEDB_GRAPH_BTN",
|
|
21914
|
+
href: graph_href,
|
|
21915
|
+
style: "margin-left:auto;",
|
|
21916
|
+
title: t("graph"),
|
|
21917
|
+
"aria-label": t("graph"),
|
|
21918
|
+
"data-i18n-title": "graph",
|
|
21919
|
+
"data-i18n-aria-label": "graph"
|
|
21920
|
+
},
|
|
21921
|
+
[[
|
|
21922
|
+
"span",
|
|
21923
|
+
{ class: "icon" },
|
|
21924
|
+
[yui_toolbar_icon("yi-hexagon-nodes")]
|
|
21925
|
+
], [
|
|
21926
|
+
"span",
|
|
21927
|
+
{ i18n: "graph" },
|
|
21928
|
+
"graph"
|
|
21929
|
+
]]
|
|
21930
|
+
]);
|
|
21906
21931
|
let $container = createElement2([
|
|
21907
21932
|
"div",
|
|
21908
21933
|
{
|
|
@@ -21983,11 +22008,12 @@ function build_ui$6(gobj) {
|
|
|
21983
22008
|
source_url
|
|
21984
22009
|
]]
|
|
21985
22010
|
],
|
|
22011
|
+
...graph_items,
|
|
21986
22012
|
[
|
|
21987
22013
|
"button",
|
|
21988
22014
|
{
|
|
21989
22015
|
class: "button TREEDB_JSON_BTN",
|
|
21990
|
-
style: "margin-left:auto;",
|
|
22016
|
+
style: graph_href ? "" : "margin-left:auto;",
|
|
21991
22017
|
title: t("raw json"),
|
|
21992
22018
|
"aria-label": t("raw json"),
|
|
21993
22019
|
"data-i18n-title": "raw json",
|
|
@@ -22190,13 +22216,103 @@ function card_action_anchor(logical_class, icon, i18n_key, href) {
|
|
|
22190
22216
|
];
|
|
22191
22217
|
}
|
|
22192
22218
|
/************************************************************
|
|
22219
|
+
* What a topic card says about its topic, from its desc alone
|
|
22220
|
+
* (no request): its version and how many columns it has, the
|
|
22221
|
+
* topics it hangs FROM (its fkeys) and the ones that hang from
|
|
22222
|
+
* it (its hooks). The names are DATA and are not translated;
|
|
22223
|
+
* each label carries its key. Lists are cut with an ellipsis,
|
|
22224
|
+
* whole in the title.
|
|
22225
|
+
************************************************************/
|
|
22226
|
+
function topic_card_meta(desc) {
|
|
22227
|
+
if (!is_object(desc)) return [];
|
|
22228
|
+
let cols = is_array(desc.cols) ? desc.cols : [];
|
|
22229
|
+
let n_cols = 0;
|
|
22230
|
+
let parents = [];
|
|
22231
|
+
let children = [];
|
|
22232
|
+
for (let col of cols) {
|
|
22233
|
+
if (!col || !col.id || col.id.charAt(0) === "_") continue;
|
|
22234
|
+
n_cols++;
|
|
22235
|
+
if (is_object(col.fkey)) {
|
|
22236
|
+
for (let t_name of Object.keys(col.fkey)) if (!parents.includes(t_name)) parents.push(t_name);
|
|
22237
|
+
}
|
|
22238
|
+
if (is_object(col.hook)) {
|
|
22239
|
+
for (let t_name of Object.keys(col.hook)) if (!children.includes(t_name)) children.push(t_name);
|
|
22240
|
+
}
|
|
22241
|
+
}
|
|
22242
|
+
let meta = [];
|
|
22243
|
+
let head = [];
|
|
22244
|
+
if (desc.topic_version !== void 0 && desc.topic_version !== null && desc.topic_version !== "") head.push([
|
|
22245
|
+
"span",
|
|
22246
|
+
{
|
|
22247
|
+
class: "TREEDB_TOPIC_CARD_VERSION",
|
|
22248
|
+
title: t("version"),
|
|
22249
|
+
"data-i18n-title": "version"
|
|
22250
|
+
},
|
|
22251
|
+
`v${desc.topic_version}`
|
|
22252
|
+
]);
|
|
22253
|
+
head.push([
|
|
22254
|
+
"span",
|
|
22255
|
+
{ class: "TREEDB_TOPIC_CARD_COLS" },
|
|
22256
|
+
[[
|
|
22257
|
+
"span",
|
|
22258
|
+
{},
|
|
22259
|
+
`${n_cols}`
|
|
22260
|
+
], [
|
|
22261
|
+
"span",
|
|
22262
|
+
{ i18n: "columns" },
|
|
22263
|
+
"columns"
|
|
22264
|
+
]]
|
|
22265
|
+
]);
|
|
22266
|
+
meta.push([
|
|
22267
|
+
"div",
|
|
22268
|
+
{ class: "TREEDB_TOPIC_CARD_META" },
|
|
22269
|
+
head
|
|
22270
|
+
]);
|
|
22271
|
+
let relation = (cls, key, arrow, names) => {
|
|
22272
|
+
let list = names.join(", ");
|
|
22273
|
+
return [
|
|
22274
|
+
"div",
|
|
22275
|
+
{
|
|
22276
|
+
class: `TREEDB_TOPIC_CARD_REL ${cls}`,
|
|
22277
|
+
title: list
|
|
22278
|
+
},
|
|
22279
|
+
[
|
|
22280
|
+
[
|
|
22281
|
+
"span",
|
|
22282
|
+
{
|
|
22283
|
+
class: "TREEDB_TOPIC_CARD_REL_ARROW",
|
|
22284
|
+
"aria-hidden": "true"
|
|
22285
|
+
},
|
|
22286
|
+
arrow
|
|
22287
|
+
],
|
|
22288
|
+
[
|
|
22289
|
+
"span",
|
|
22290
|
+
{
|
|
22291
|
+
class: "TREEDB_TOPIC_CARD_REL_LABEL",
|
|
22292
|
+
i18n: key
|
|
22293
|
+
},
|
|
22294
|
+
key
|
|
22295
|
+
],
|
|
22296
|
+
[
|
|
22297
|
+
"span",
|
|
22298
|
+
{ class: "TREEDB_TOPIC_CARD_REL_LIST" },
|
|
22299
|
+
list
|
|
22300
|
+
]
|
|
22301
|
+
]
|
|
22302
|
+
];
|
|
22303
|
+
};
|
|
22304
|
+
if (parents.length) meta.push(relation("TREEDB_TOPIC_CARD_PARENTS", "parents", "↑", parents));
|
|
22305
|
+
if (children.length) meta.push(relation("TREEDB_TOPIC_CARD_CHILDREN", "children", "↓", children));
|
|
22306
|
+
return meta;
|
|
22307
|
+
}
|
|
22308
|
+
/************************************************************
|
|
22193
22309
|
* Add one topic card to the cards-landing grid (list->detail).
|
|
22194
22310
|
* With `card_action_routes` (host-supplied templates) the card
|
|
22195
22311
|
* shows three hash-routed icons — info / table / graph. Without,
|
|
22196
22312
|
* it falls back to a single card that opens the table (same id
|
|
22197
22313
|
* contract as the tab, `<gobj>?<topic>`).
|
|
22198
22314
|
************************************************************/
|
|
22199
|
-
function add_topic_card(gobj, id, text, icon) {
|
|
22315
|
+
function add_topic_card(gobj, id, text, icon, desc) {
|
|
22200
22316
|
let $grid = gobj_read_attr(gobj, "$container").querySelector(".TREEDB_TOPICS_LANDING .yui-nav-cards");
|
|
22201
22317
|
if (!$grid) return;
|
|
22202
22318
|
let routes = gobj_read_attr(gobj, "card_action_routes");
|
|
@@ -22239,25 +22355,28 @@ function add_topic_card(gobj, id, text, icon) {
|
|
|
22239
22355
|
let actions = [];
|
|
22240
22356
|
if (routes.info) actions.push(card_action_anchor("TREEDB_CARD_INFO", "yi-circle-info", "info", fill(routes.info)));
|
|
22241
22357
|
if (routes.table) actions.push(card_action_anchor("TREEDB_CARD_TABLE", "yi-table", "table", fill(routes.table)));
|
|
22242
|
-
if (routes.graph) actions.push(card_action_anchor("TREEDB_CARD_GRAPH", "yi-hexagon-nodes", "graph", fill(routes.graph)));
|
|
22243
22358
|
let $card = createElement2([
|
|
22244
22359
|
"div",
|
|
22245
22360
|
{
|
|
22246
22361
|
class: "TREEDB_TOPIC_CARD",
|
|
22247
22362
|
"data-topic": topic
|
|
22248
22363
|
},
|
|
22249
|
-
[
|
|
22250
|
-
|
|
22251
|
-
|
|
22252
|
-
|
|
22253
|
-
|
|
22254
|
-
|
|
22255
|
-
|
|
22256
|
-
|
|
22257
|
-
|
|
22258
|
-
|
|
22259
|
-
|
|
22260
|
-
|
|
22364
|
+
[
|
|
22365
|
+
[
|
|
22366
|
+
"span",
|
|
22367
|
+
{
|
|
22368
|
+
class: "TREEDB_TOPIC_CARD_NAME",
|
|
22369
|
+
i18n: text
|
|
22370
|
+
},
|
|
22371
|
+
text
|
|
22372
|
+
],
|
|
22373
|
+
...topic_card_meta(desc),
|
|
22374
|
+
[
|
|
22375
|
+
"div",
|
|
22376
|
+
{ class: "TREEDB_TOPIC_CARD_ACTIONS" },
|
|
22377
|
+
actions
|
|
22378
|
+
]
|
|
22379
|
+
]
|
|
22261
22380
|
]);
|
|
22262
22381
|
if (gobj.priv._selected_card_topic === topic) $card.classList.add("is-selected");
|
|
22263
22382
|
$card.addEventListener("click", function() {
|
|
@@ -22610,7 +22729,7 @@ function process_treedb_descs$1(gobj) {
|
|
|
22610
22729
|
let id = `${gobj_name(gobj)}?${desc.topic_name}`;
|
|
22611
22730
|
let gobj_topic_form = gobj_create_service(id, "C_YUI_TREEDB_TOPIC_WITH_FORM", kw_topic_form, gobj);
|
|
22612
22731
|
add_tab(gobj, gobj_topic_form, id, key, "yi-table");
|
|
22613
|
-
add_topic_card(gobj, id, key, "yi-table");
|
|
22732
|
+
add_topic_card(gobj, id, key, "yi-table", desc);
|
|
22614
22733
|
gobj_start(gobj_topic_form);
|
|
22615
22734
|
}
|
|
22616
22735
|
let href = gobj_read_str_attr(gobj, "last_selection");
|
package/package.json
CHANGED
|
@@ -36,6 +36,31 @@
|
|
|
36
36
|
line-height: 1.2;
|
|
37
37
|
word-break: break-word;
|
|
38
38
|
}
|
|
39
|
+
/* What the card says about its topic: version + columns, then the
|
|
40
|
+
* topics it hangs from and the ones hanging from it. Muted and small,
|
|
41
|
+
* under the name; a long list is cut, whole in the title. The spans
|
|
42
|
+
* are spaced by `gap` because createElement2 trims text nodes. */
|
|
43
|
+
.TREEDB_TOPIC_CARD_META,
|
|
44
|
+
.TREEDB_TOPIC_CARD_REL {
|
|
45
|
+
display: flex;
|
|
46
|
+
align-items: baseline;
|
|
47
|
+
justify-content: center;
|
|
48
|
+
gap: 0.3rem;
|
|
49
|
+
max-width: 100%;
|
|
50
|
+
font-size: 0.75rem;
|
|
51
|
+
color: var(--bulma-text-weak, #7a7a7a);
|
|
52
|
+
white-space: nowrap;
|
|
53
|
+
}
|
|
54
|
+
.TREEDB_TOPIC_CARD_COLS {
|
|
55
|
+
display: inline-flex;
|
|
56
|
+
gap: 0.25rem;
|
|
57
|
+
}
|
|
58
|
+
.TREEDB_TOPIC_CARD_REL_LIST {
|
|
59
|
+
min-width: 0;
|
|
60
|
+
overflow: hidden;
|
|
61
|
+
text-overflow: ellipsis;
|
|
62
|
+
color: var(--bulma-text, inherit);
|
|
63
|
+
}
|
|
39
64
|
.TREEDB_TOPIC_CARD_ACTIONS {
|
|
40
65
|
display: flex;
|
|
41
66
|
justify-content: center;
|
|
@@ -84,7 +84,7 @@ SDATA(data_type_t.DTP_BOOLEAN, "system", 0, false, "Manage system t
|
|
|
84
84
|
SDATA(data_type_t.DTP_STRING, "tabs_style", 0, "is-toggle is-fullwidth", "Bulma tab styling"),
|
|
85
85
|
SDATA(data_type_t.DTP_BOOLEAN, "with_cards_landing",0, false, "Land on a grid of topic cards (list->detail): a card opens its table, with the tabs bar + a back-to-grid button. Off = tabs only (legacy)."),
|
|
86
86
|
SDATA(data_type_t.DTP_BOOLEAN, "readonly", 0, false, "The whole treedb is read-only: every topic opens without its write affordances and the write events are refused. Set it when this yuno is not the MASTER of the treedb's tranger -- only the master can write, and the yuno answers 'READ-ONLY' to a write since SDK 7.13.0 (ask `treedb-info`)"),
|
|
87
|
-
SDATA(data_type_t.DTP_JSON, "card_action_routes",0, null, "
|
|
87
|
+
SDATA(data_type_t.DTP_JSON, "card_action_routes",0, null, "Hash-route templates {info, table, graph} with a {topic} placeholder (host-supplied, route-agnostic). Present ⇒ cards show the info and table icons, and `graph` without its `/{topic}` is the toolbar's graph button (the card has no graph icon: its topic segment is a focus); absent ⇒ a single card that opens the table."),
|
|
88
88
|
SDATA(data_type_t.DTP_JSON, "landing_routes", 0, null, "Host-supplied hashes for the two landing sub-views {cards, schema}; the toggle navigates to them so the landing is URL-addressable (ROUTING.md). Absent ⇒ toggle flips in-view only (legacy)."),
|
|
89
89
|
SDATA(data_type_t.DTP_STRING, "base_route", 0, "", "This view's base route (host-supplied); used to declare its sub-routes (topics / info / schema) to the site map (ROUTING.md contributor)."),
|
|
90
90
|
SDATA(data_type_t.DTP_STRING, "source_url", 0, "", "The backend this view browses (host-supplied, typically the wss url of the connection), shown in the toolbar. A tab label names the TREEDB, and the same treedb name lives on more than one node, so the node has to be readable somewhere -- and a tab is too narrow to carry a url. Empty ⇒ nothing is shown."),
|
|
@@ -254,6 +254,29 @@ function build_ui(gobj)
|
|
|
254
254
|
{
|
|
255
255
|
let source_url = gobj_read_str_attr(gobj, "source_url") || "";
|
|
256
256
|
|
|
257
|
+
/* The whole treedb as a graph, with NO topic focused. A card's graph
|
|
258
|
+
* icon lands on `<graph route>/<topic>`, and that segment is a
|
|
259
|
+
* FOCUS: going through a card was the only way in, and it always
|
|
260
|
+
* arrived with that topic highlighted. The route is the card's
|
|
261
|
+
* template without its `/{topic}`; a host whose template does not
|
|
262
|
+
* end in it, or gives none, gets no button. */
|
|
263
|
+
let routes = gobj_read_attr(gobj, "card_action_routes");
|
|
264
|
+
let graph_tpl = is_object(routes) && typeof routes.graph === "string"? routes.graph : "";
|
|
265
|
+
let graph_href = /\/\{topic\}$/.test(graph_tpl)? graph_tpl.replace(/\/\{topic\}$/, "") : "";
|
|
266
|
+
let graph_items = [];
|
|
267
|
+
if(graph_href) {
|
|
268
|
+
graph_items.push(
|
|
269
|
+
['a', {class: 'button TREEDB_GRAPH_BTN',
|
|
270
|
+
href: graph_href,
|
|
271
|
+
style: 'margin-left:auto;',
|
|
272
|
+
title: t('graph'), 'aria-label': t('graph'),
|
|
273
|
+
'data-i18n-title': 'graph', 'data-i18n-aria-label': 'graph'}, [
|
|
274
|
+
['span', {class: 'icon'}, [yui_toolbar_icon('yi-hexagon-nodes')]],
|
|
275
|
+
['span', {i18n: 'graph'}, 'graph']
|
|
276
|
+
]]
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
|
|
257
280
|
/*----------------------------------------------*
|
|
258
281
|
* Layout Schema
|
|
259
282
|
*----------------------------------------------*/
|
|
@@ -262,12 +285,15 @@ function build_ui(gobj)
|
|
|
262
285
|
['div', {class: 'is-flex-grow-0'}, [
|
|
263
286
|
['div', {class: 'is-flex is-align-items-center TREEDB_TOPICS_TOOLBAR',
|
|
264
287
|
style: 'gap:.25rem; padding:.25rem .25rem;'}, [
|
|
265
|
-
/* This toolbar never holds more than
|
|
266
|
-
* (back|toggle on the left, json on the right),
|
|
267
|
-
* labels stay on mobile — a deliberate exception
|
|
268
|
-
* icon-only-on-mobile rule:
|
|
269
|
-
* read as the same control
|
|
270
|
-
*
|
|
288
|
+
/* This toolbar never holds more than THREE buttons at once
|
|
289
|
+
* (back|toggle on the left, graph and json on the right),
|
|
290
|
+
* so the labels stay on mobile — a deliberate exception
|
|
291
|
+
* to the icon-only-on-mobile rule: bare squares side by
|
|
292
|
+
* side read as the same control, and the toggle and the
|
|
293
|
+
* graph wear the same icon. They fit at 360px because the
|
|
294
|
+
* source url between them gives way down to its icon. The
|
|
295
|
+
* graph's toolbar has many more, so it keeps
|
|
296
|
+
* is-hidden-mobile. */
|
|
271
297
|
|
|
272
298
|
/* Back to the topic-cards grid (cards-landing mode only);
|
|
273
299
|
* hidden until a topic is open. */
|
|
@@ -309,11 +335,14 @@ function build_ui(gobj)
|
|
|
309
335
|
['span', {class: 'icon'}, [yui_toolbar_icon('yi-cloudversify')]],
|
|
310
336
|
['span', {class: 'TREEDB_TOPICS_SOURCE_URL'}, source_url]
|
|
311
337
|
]],
|
|
338
|
+
...graph_items,
|
|
312
339
|
/* Inspect the treedb's raw tranger json (whole service,
|
|
313
|
-
* print-tranger, lazy drill). Last
|
|
314
|
-
*
|
|
340
|
+
* print-tranger, lazy drill). Last and flush right, away
|
|
341
|
+
* from the back arrow it sat next to: the `margin-left:
|
|
342
|
+
* auto` goes on the first button of the right group,
|
|
343
|
+
* which is the graph one when there is one. */
|
|
315
344
|
['button', {class: 'button TREEDB_JSON_BTN',
|
|
316
|
-
style: 'margin-left:auto;',
|
|
345
|
+
style: graph_href? '' : 'margin-left:auto;',
|
|
317
346
|
title: t('raw json'), 'aria-label': t('raw json'),
|
|
318
347
|
'data-i18n-title': 'raw json', 'data-i18n-aria-label': 'raw json'}, [
|
|
319
348
|
['span', {class: 'icon'}, [yui_toolbar_icon('yi-eye')]],
|
|
@@ -570,6 +599,74 @@ function card_action_anchor(logical_class, icon, i18n_key, href)
|
|
|
570
599
|
]];
|
|
571
600
|
}
|
|
572
601
|
|
|
602
|
+
/************************************************************
|
|
603
|
+
* What a topic card says about its topic, from its desc alone
|
|
604
|
+
* (no request): its version and how many columns it has, the
|
|
605
|
+
* topics it hangs FROM (its fkeys) and the ones that hang from
|
|
606
|
+
* it (its hooks). The names are DATA and are not translated;
|
|
607
|
+
* each label carries its key. Lists are cut with an ellipsis,
|
|
608
|
+
* whole in the title.
|
|
609
|
+
************************************************************/
|
|
610
|
+
function topic_card_meta(desc)
|
|
611
|
+
{
|
|
612
|
+
if(!is_object(desc)) {
|
|
613
|
+
return [];
|
|
614
|
+
}
|
|
615
|
+
let cols = is_array(desc.cols)? desc.cols : [];
|
|
616
|
+
let n_cols = 0;
|
|
617
|
+
let parents = [];
|
|
618
|
+
let children = [];
|
|
619
|
+
for(let col of cols) {
|
|
620
|
+
if(!col || !col.id || col.id.charAt(0) === "_") {
|
|
621
|
+
continue;
|
|
622
|
+
}
|
|
623
|
+
n_cols++;
|
|
624
|
+
if(is_object(col.fkey)) {
|
|
625
|
+
for(let t_name of Object.keys(col.fkey)) {
|
|
626
|
+
if(!parents.includes(t_name)) {
|
|
627
|
+
parents.push(t_name);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
if(is_object(col.hook)) {
|
|
632
|
+
for(let t_name of Object.keys(col.hook)) {
|
|
633
|
+
if(!children.includes(t_name)) {
|
|
634
|
+
children.push(t_name);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
let meta = [];
|
|
641
|
+
let head = [];
|
|
642
|
+
if(desc.topic_version !== undefined && desc.topic_version !== null && desc.topic_version !== "") {
|
|
643
|
+
head.push(['span', {class: 'TREEDB_TOPIC_CARD_VERSION',
|
|
644
|
+
title: t('version'), 'data-i18n-title': 'version'},
|
|
645
|
+
`v${desc.topic_version}`]);
|
|
646
|
+
}
|
|
647
|
+
head.push(['span', {class: 'TREEDB_TOPIC_CARD_COLS'}, [
|
|
648
|
+
['span', {}, `${n_cols}`],
|
|
649
|
+
['span', {i18n: 'columns'}, 'columns']
|
|
650
|
+
]]);
|
|
651
|
+
meta.push(['div', {class: 'TREEDB_TOPIC_CARD_META'}, head]);
|
|
652
|
+
|
|
653
|
+
let relation = (cls, key, arrow, names) => {
|
|
654
|
+
let list = names.join(", ");
|
|
655
|
+
return ['div', {class: `TREEDB_TOPIC_CARD_REL ${cls}`, title: list}, [
|
|
656
|
+
['span', {class: 'TREEDB_TOPIC_CARD_REL_ARROW', 'aria-hidden': 'true'}, arrow],
|
|
657
|
+
['span', {class: 'TREEDB_TOPIC_CARD_REL_LABEL', i18n: key}, key],
|
|
658
|
+
['span', {class: 'TREEDB_TOPIC_CARD_REL_LIST'}, list]
|
|
659
|
+
]];
|
|
660
|
+
};
|
|
661
|
+
if(parents.length) {
|
|
662
|
+
meta.push(relation('TREEDB_TOPIC_CARD_PARENTS', 'parents', '↑', parents));
|
|
663
|
+
}
|
|
664
|
+
if(children.length) {
|
|
665
|
+
meta.push(relation('TREEDB_TOPIC_CARD_CHILDREN', 'children', '↓', children));
|
|
666
|
+
}
|
|
667
|
+
return meta;
|
|
668
|
+
}
|
|
669
|
+
|
|
573
670
|
/************************************************************
|
|
574
671
|
* Add one topic card to the cards-landing grid (list->detail).
|
|
575
672
|
* With `card_action_routes` (host-supplied templates) the card
|
|
@@ -577,7 +674,7 @@ function card_action_anchor(logical_class, icon, i18n_key, href)
|
|
|
577
674
|
* it falls back to a single card that opens the table (same id
|
|
578
675
|
* contract as the tab, `<gobj>?<topic>`).
|
|
579
676
|
************************************************************/
|
|
580
|
-
function add_topic_card(gobj, id, text, icon)
|
|
677
|
+
function add_topic_card(gobj, id, text, icon, desc)
|
|
581
678
|
{
|
|
582
679
|
let $container = gobj_read_attr(gobj, "$container");
|
|
583
680
|
let $grid = $container.querySelector(".TREEDB_TOPICS_LANDING .yui-nav-cards");
|
|
@@ -606,9 +703,16 @@ function add_topic_card(gobj, id, text, icon)
|
|
|
606
703
|
return;
|
|
607
704
|
}
|
|
608
705
|
|
|
609
|
-
/*
|
|
610
|
-
*
|
|
611
|
-
*
|
|
706
|
+
/* Two-icon card: info / table, real hash anchors. {topic} in each
|
|
707
|
+
* template is the raw topic name (identifier-safe, matching the
|
|
708
|
+
* tab/host `<base_route>/<topic>` convention).
|
|
709
|
+
*
|
|
710
|
+
* NO graph icon any more. Its route was `<graph>/<topic>`, and that
|
|
711
|
+
* segment is a FOCUS: every way into the graph from a card arrived
|
|
712
|
+
* with that topic highlighted, over whatever the reader had left
|
|
713
|
+
* there. The graph is one button in the toolbar now, with no topic
|
|
714
|
+
* (routes.graph still feeds it), and the room goes to what the card
|
|
715
|
+
* can say about its topic. */
|
|
612
716
|
let topic = id.indexOf("?") >= 0 ? id.split("?")[1] : id;
|
|
613
717
|
let fill = (tpl) => String(tpl || "").replace("{topic}", topic);
|
|
614
718
|
|
|
@@ -621,14 +725,11 @@ function add_topic_card(gobj, id, text, icon)
|
|
|
621
725
|
actions.push(card_action_anchor(
|
|
622
726
|
"TREEDB_CARD_TABLE", "yi-table", "table", fill(routes.table)));
|
|
623
727
|
}
|
|
624
|
-
if(routes.graph) {
|
|
625
|
-
actions.push(card_action_anchor(
|
|
626
|
-
"TREEDB_CARD_GRAPH", "yi-hexagon-nodes", "graph", fill(routes.graph)));
|
|
627
|
-
}
|
|
628
728
|
|
|
629
729
|
let $card = createElement2(
|
|
630
730
|
['div', {class: 'TREEDB_TOPIC_CARD', 'data-topic': topic}, [
|
|
631
731
|
['span', {class: 'TREEDB_TOPIC_CARD_NAME', i18n: text}, text],
|
|
732
|
+
...topic_card_meta(desc),
|
|
632
733
|
['div', {class: 'TREEDB_TOPIC_CARD_ACTIONS'}, actions]
|
|
633
734
|
]]
|
|
634
735
|
);
|
|
@@ -1058,7 +1159,7 @@ function process_treedb_descs(gobj)
|
|
|
1058
1159
|
|
|
1059
1160
|
// TODO get icon from remote config
|
|
1060
1161
|
add_tab(gobj, gobj_topic_form, id, key, "yi-table");
|
|
1061
|
-
add_topic_card(gobj, id, key, "yi-table");
|
|
1162
|
+
add_topic_card(gobj, id, key, "yi-table", desc);
|
|
1062
1163
|
|
|
1063
1164
|
gobj_start(gobj_topic_form);
|
|
1064
1165
|
}
|