@blokkli/editor 2.0.0-alpha.61 → 2.0.0-alpha.63

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.
Files changed (128) hide show
  1. package/dist/global/types/colorOptions.d.ts +16 -0
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +168 -14
  4. package/dist/modules/agent/runtime/app/components/Conversation/Item/Assistant/index.vue +14 -5
  5. package/dist/modules/agent/runtime/app/features/agent/ConversationsAdmin/ConversationsTab/Item.vue +2 -2
  6. package/dist/modules/agent/runtime/app/features/agent/ConversationsAdmin/RatingsTab/Item.vue +2 -2
  7. package/dist/modules/agent/runtime/app/features/agent/ConversationsAdmin/SplitView/ConversationDetail.vue +2 -2
  8. package/dist/modules/agent/runtime/app/features/agent/Transcript/MessageContent.vue +14 -1
  9. package/dist/modules/agent/runtime/app/features/agent/Transcript/index.vue +30 -12
  10. package/dist/modules/agent/runtime/app/helpers/linkifyBlockUuids.d.ts +11 -0
  11. package/dist/modules/agent/runtime/app/helpers/linkifyBlockUuids.js +47 -0
  12. package/dist/modules/agent/runtime/app/tools/auto_translate_paragraphs/Component.d.vue.ts +22 -0
  13. package/dist/modules/agent/runtime/app/tools/auto_translate_paragraphs/Component.vue +28 -26
  14. package/dist/modules/agent/runtime/app/tools/auto_translate_paragraphs/Component.vue.d.ts +22 -0
  15. package/dist/modules/agent/runtime/app/tools/auto_translate_paragraphs/index.d.ts +15 -0
  16. package/dist/modules/agent/runtime/app/tools/delegate_text_rewrite/Component.d.vue.ts +22 -0
  17. package/dist/modules/agent/runtime/app/tools/delegate_text_rewrite/Component.vue +59 -16
  18. package/dist/modules/agent/runtime/app/tools/delegate_text_rewrite/Component.vue.d.ts +22 -0
  19. package/dist/modules/agent/runtime/app/tools/delegate_text_rewrite/index.d.ts +15 -0
  20. package/dist/modules/agent/runtime/app/tools/fieldDiffApproval.d.ts +85 -15
  21. package/dist/modules/agent/runtime/app/tools/fieldDiffApproval.js +138 -28
  22. package/dist/modules/agent/runtime/app/tools/schemas.d.ts +15 -5
  23. package/dist/modules/agent/runtime/app/tools/schemas.js +29 -12
  24. package/dist/modules/agent/runtime/app/tools/search_text/index.js +1 -1
  25. package/dist/modules/agent/runtime/app/tools/update_text_fields/Component.d.vue.ts +22 -0
  26. package/dist/modules/agent/runtime/app/tools/update_text_fields/Component.vue +54 -30
  27. package/dist/modules/agent/runtime/app/tools/update_text_fields/Component.vue.d.ts +22 -0
  28. package/dist/modules/agent/runtime/app/tools/update_text_fields/index.d.ts +15 -0
  29. package/dist/modules/agent/runtime/server/default-system-prompts/architecture.js +1 -1
  30. package/dist/modules/agent/runtime/server/default-system-prompts/important-rules.js +1 -0
  31. package/dist/modules/charts/runtime/blokkli/tools/chart_schemas.d.ts +1 -1
  32. package/dist/modules/charts/runtime/blokkli/tools/chart_schemas.js +12 -5
  33. package/dist/modules/charts/runtime/components/ChartRenderer/index.vue +7 -16
  34. package/dist/modules/charts/runtime/features/charts/Editor/ColorDropdown/index.vue +7 -77
  35. package/dist/modules/charts/runtime/features/charts/Editor/CsvImport/csvHelpers.d.ts +1 -1
  36. package/dist/modules/charts/runtime/features/charts/Editor/useChartEditorState.d.ts +1 -1
  37. package/dist/modules/charts/runtime/helpers/index.d.ts +2 -1
  38. package/dist/modules/charts/runtime/helpers/index.js +4 -2
  39. package/dist/modules/drupal/graphql/base/fragment.paragraphsBlokkliMutationResult.graphql +3 -0
  40. package/dist/modules/drupal/runtime/adapter/index.js +38 -27
  41. package/dist/runtime/composables/useBlokkliRuntimeConfig.d.ts +50 -0
  42. package/dist/runtime/composables/useBlokkliRuntimeConfig.js +34 -0
  43. package/dist/runtime/editor/adapter/index.d.ts +2 -1
  44. package/dist/runtime/editor/components/ColorDropdown/index.d.vue.ts +26 -0
  45. package/dist/runtime/editor/components/ColorDropdown/index.vue +116 -0
  46. package/dist/runtime/editor/components/ColorDropdown/index.vue.d.ts +26 -0
  47. package/dist/runtime/editor/components/DiffApproval/Highlight/Item.d.vue.ts +14 -20
  48. package/dist/runtime/editor/components/DiffApproval/Highlight/Item.vue +97 -52
  49. package/dist/runtime/editor/components/DiffApproval/Highlight/Item.vue.d.ts +14 -20
  50. package/dist/runtime/editor/components/DiffApproval/Highlight/index.d.vue.ts +6 -6
  51. package/dist/runtime/editor/components/DiffApproval/Highlight/index.vue +30 -21
  52. package/dist/runtime/editor/components/DiffApproval/Highlight/index.vue.d.ts +6 -6
  53. package/dist/runtime/editor/components/DiffApproval/Toolbar/index.d.vue.ts +19 -9
  54. package/dist/runtime/editor/components/DiffApproval/Toolbar/index.vue +18 -9
  55. package/dist/runtime/editor/components/DiffApproval/Toolbar/index.vue.d.ts +19 -9
  56. package/dist/runtime/editor/components/DiffApproval/index.d.vue.ts +14 -6
  57. package/dist/runtime/editor/components/DiffApproval/index.vue +62 -35
  58. package/dist/runtime/editor/components/DiffApproval/index.vue.d.ts +14 -6
  59. package/dist/runtime/editor/components/DiffApproval/types.d.ts +32 -0
  60. package/dist/runtime/editor/components/DiffApproval/types.js +22 -0
  61. package/dist/runtime/editor/components/Dropdown/index.d.vue.ts +5 -4
  62. package/dist/runtime/editor/components/Dropdown/index.vue +89 -29
  63. package/dist/runtime/editor/components/Dropdown/index.vue.d.ts +5 -4
  64. package/dist/runtime/editor/components/FlexTextarea/index.d.vue.ts +1 -1
  65. package/dist/runtime/editor/components/FlexTextarea/index.vue.d.ts +1 -1
  66. package/dist/runtime/editor/components/NestedEditorOverlay/index.d.vue.ts +2 -2
  67. package/dist/runtime/editor/components/NestedEditorOverlay/index.vue +3 -3
  68. package/dist/runtime/editor/components/NestedEditorOverlay/index.vue.d.ts +2 -2
  69. package/dist/runtime/editor/components/PopupHost/index.d.vue.ts +13 -0
  70. package/dist/runtime/editor/components/PopupHost/index.vue +12 -0
  71. package/dist/runtime/editor/components/PopupHost/index.vue.d.ts +13 -0
  72. package/dist/runtime/editor/components/index.d.ts +2 -0
  73. package/dist/runtime/editor/components/index.js +2 -0
  74. package/dist/runtime/editor/css/output.css +1 -1
  75. package/dist/runtime/editor/features/analyze/Main.vue +15 -2
  76. package/dist/runtime/editor/features/analyze/Results/ResultsItemNodes.vue +4 -1
  77. package/dist/runtime/editor/features/analyze/Results/ResultsItemNodesTarget.vue +25 -16
  78. package/dist/runtime/editor/features/analyze/analyzers/defaults/validations.d.ts +10 -0
  79. package/dist/runtime/editor/features/analyze/analyzers/defaults/validations.js +39 -0
  80. package/dist/runtime/editor/features/analyze/analyzers/helpers/Context.d.ts +5 -1
  81. package/dist/runtime/editor/features/analyze/analyzers/helpers/Context.js +5 -0
  82. package/dist/runtime/editor/features/analyze/index.vue +0 -1
  83. package/dist/runtime/editor/features/changelog/changelog.json +9 -1
  84. package/dist/runtime/editor/features/comments/Comment/Meta/index.vue +1 -1
  85. package/dist/runtime/editor/features/comments/Comment/index.vue +1 -1
  86. package/dist/runtime/editor/features/publish/Dialog/Violations.d.vue.ts +12 -0
  87. package/dist/runtime/editor/features/publish/Dialog/Violations.vue +117 -0
  88. package/dist/runtime/editor/features/publish/Dialog/Violations.vue.d.ts +12 -0
  89. package/dist/runtime/editor/features/publish/Dialog/index.vue +61 -24
  90. package/dist/runtime/editor/features/publish/index.vue +2 -4
  91. package/dist/runtime/editor/features/publish/types.d.ts +0 -4
  92. package/dist/runtime/editor/helpers/color/index.d.ts +7 -0
  93. package/dist/runtime/editor/helpers/color/index.js +14 -0
  94. package/dist/runtime/editor/helpers/diff/index.d.ts +87 -0
  95. package/dist/runtime/editor/helpers/diff/index.js +256 -0
  96. package/dist/runtime/editor/helpers/injections.d.ts +11 -0
  97. package/dist/runtime/editor/helpers/injections.js +1 -0
  98. package/dist/runtime/editor/plugins/Sidebar/Detached/index.d.vue.ts +1 -1
  99. package/dist/runtime/editor/plugins/Sidebar/Detached/index.vue.d.ts +1 -1
  100. package/dist/runtime/editor/plugins/Sidebar/index.d.vue.ts +2 -2
  101. package/dist/runtime/editor/plugins/Sidebar/index.vue.d.ts +2 -2
  102. package/dist/runtime/editor/providers/analyze.js +5 -2
  103. package/dist/runtime/editor/providers/config.d.ts +3 -1
  104. package/dist/runtime/editor/providers/config.js +46 -15
  105. package/dist/runtime/editor/providers/state.d.ts +13 -0
  106. package/dist/runtime/editor/providers/state.js +7 -0
  107. package/dist/runtime/editor/translations/de.json +7 -4
  108. package/dist/runtime/editor/translations/fr.json +2 -4
  109. package/dist/runtime/editor/translations/gsw_CH.json +7 -4
  110. package/dist/runtime/editor/translations/it.json +2 -4
  111. package/dist/runtime/helpers/colors.d.ts +39 -0
  112. package/dist/runtime/helpers/colors.js +28 -0
  113. package/dist/runtime/types/colors.d.ts +11 -0
  114. package/package.json +1 -1
  115. package/dist/runtime/editor/features/validations/Overlay/Item.d.vue.ts +0 -7
  116. package/dist/runtime/editor/features/validations/Overlay/Item.vue +0 -36
  117. package/dist/runtime/editor/features/validations/Overlay/Item.vue.d.ts +0 -7
  118. package/dist/runtime/editor/features/validations/Overlay/index.d.vue.ts +0 -7
  119. package/dist/runtime/editor/features/validations/Overlay/index.vue +0 -115
  120. package/dist/runtime/editor/features/validations/Overlay/index.vue.d.ts +0 -7
  121. package/dist/runtime/editor/features/validations/SidebarItem/index.d.vue.ts +0 -10
  122. package/dist/runtime/editor/features/validations/SidebarItem/index.vue +0 -41
  123. package/dist/runtime/editor/features/validations/SidebarItem/index.vue.d.ts +0 -10
  124. package/dist/runtime/editor/features/validations/index.d.vue.ts +0 -3
  125. package/dist/runtime/editor/features/validations/index.vue +0 -91
  126. package/dist/runtime/editor/features/validations/index.vue.d.ts +0 -3
  127. package/dist/runtime/editor/types/config.d.ts +0 -5
  128. /package/dist/runtime/{editor/types/config.js → types/colors.js} +0 -0
@@ -1,4 +1,20 @@
1
+ /**
2
+ * A color option declared at build time.
3
+ *
4
+ * Two shapes:
5
+ * - A flat color with a single hex value.
6
+ * - A ramped color with a map of shades and an explicit `mainShade` that
7
+ * identifies which shade is the canonical/base swatch.
8
+ *
9
+ * For ramped colors, a chart can reference the base via the bare color id
10
+ * (e.g. `red`) or any specific shade via the compound id `red.<shade>` (e.g.
11
+ * `red.300`).
12
+ */
1
13
  export type ColorOption = {
14
+ label: string;
2
15
  hex: string;
16
+ } | {
3
17
  label: string;
18
+ shades: Record<string, string>;
19
+ mainShade: string;
4
20
  };
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@blokkli/editor",
3
3
  "configKey": "blokkli",
4
- "version": "2.0.0-alpha.61",
4
+ "version": "2.0.0-alpha.63",
5
5
  "compatibility": {
6
6
  "nuxt": ">=3.15.0"
7
7
  },
package/dist/module.mjs CHANGED
@@ -19,7 +19,7 @@ import 'typescript';
19
19
  import 'oxc-walker';
20
20
 
21
21
  const name = "@blokkli/editor";
22
- const version = "2.0.0-alpha.61";
22
+ const version = "2.0.0-alpha.63";
23
23
 
24
24
  function validateOption(optionKey, option, icons) {
25
25
  const errors = [];
@@ -1008,6 +1008,95 @@ class FileCache {
1008
1008
  }
1009
1009
  }
1010
1010
 
1011
+ const HEX_COLOR_REGEX = /^#(?:[\da-f]{3}|[\da-f]{6})$/i;
1012
+ const VALID_ID_REGEX = /^[a-z_$][\w$]*$/i;
1013
+ function isHex(value) {
1014
+ return typeof value === "string" && HEX_COLOR_REGEX.test(value);
1015
+ }
1016
+ function isNonEmptyString(value) {
1017
+ return typeof value === "string" && value.length > 0;
1018
+ }
1019
+ function hasShades(option) {
1020
+ return "shades" in option && !!option.shades && typeof option.shades === "object";
1021
+ }
1022
+ function validateColorOption(colorId, option) {
1023
+ const errors = [];
1024
+ if (!VALID_ID_REGEX.test(colorId)) {
1025
+ errors.push({
1026
+ message: `Color id "${colorId}" is not a valid JavaScript identifier (must start with a letter, underscore or $, followed by letters, digits, underscores or $). Color ids may not contain "." \u2014 that character is reserved for shade-qualified ids (e.g. "red.300").`,
1027
+ optionKey: colorId
1028
+ });
1029
+ }
1030
+ if (!isNonEmptyString(option.label)) {
1031
+ errors.push({
1032
+ message: `Option "${colorId}" is missing a non-empty "label".`,
1033
+ optionKey: colorId
1034
+ });
1035
+ }
1036
+ if (hasShades(option)) {
1037
+ const shadeKeys = Object.keys(option.shades);
1038
+ if (shadeKeys.length === 0) {
1039
+ errors.push({
1040
+ message: `Option "${colorId}" declares an empty "shades" object. Either omit "shades" or declare at least one shade.`,
1041
+ optionKey: colorId
1042
+ });
1043
+ }
1044
+ for (const shadeKey of shadeKeys) {
1045
+ const shadeValue = option.shades[shadeKey];
1046
+ if (!isHex(shadeValue)) {
1047
+ errors.push({
1048
+ message: `Option "${colorId}" shade "${shadeKey}" has value "${shadeValue}" which is not a valid hex color (expected format: #RRGGBB or #RGB)`,
1049
+ optionKey: colorId
1050
+ });
1051
+ }
1052
+ }
1053
+ if (!isNonEmptyString(option.mainShade)) {
1054
+ errors.push({
1055
+ message: `Option "${colorId}" declares "shades" but is missing "mainShade".`,
1056
+ optionKey: colorId
1057
+ });
1058
+ } else if (!shadeKeys.includes(option.mainShade)) {
1059
+ errors.push({
1060
+ message: `Option "${colorId}" mainShade "${option.mainShade}" is not a key of shades (available: ${shadeKeys.map((k) => `"${k}"`).join(", ")})`,
1061
+ optionKey: colorId
1062
+ });
1063
+ }
1064
+ if ("hex" in option) {
1065
+ errors.push({
1066
+ message: `Option "${colorId}" declares both "hex" and "shades". Use one or the other: shaded colors derive their base hex from "shades[mainShade]".`,
1067
+ optionKey: colorId
1068
+ });
1069
+ }
1070
+ } else {
1071
+ const hex = option.hex;
1072
+ if (hex === void 0) {
1073
+ errors.push({
1074
+ message: `Option "${colorId}": "hex" is required when "shades" is not provided.`,
1075
+ optionKey: colorId
1076
+ });
1077
+ } else if (!isHex(hex)) {
1078
+ errors.push({
1079
+ message: `Option "${colorId}" has hex value "${hex}" which is not a valid hex color (expected format: #RRGGBB or #RGB)`,
1080
+ optionKey: colorId
1081
+ });
1082
+ }
1083
+ }
1084
+ return errors;
1085
+ }
1086
+ function validateColorOptions(colorOptions) {
1087
+ if (!colorOptions) {
1088
+ return [];
1089
+ }
1090
+ const errors = [];
1091
+ for (const [colorId, option] of Object.entries(colorOptions)) {
1092
+ if (!option || typeof option !== "object") {
1093
+ continue;
1094
+ }
1095
+ errors.push(...validateColorOption(colorId, option));
1096
+ }
1097
+ return errors;
1098
+ }
1099
+
1011
1100
  const defaultColorOptions = {
1012
1101
  blue: { hex: "#3b82f6", label: "Blue" },
1013
1102
  red: { hex: "#ef4444", label: "Red" },
@@ -1221,9 +1310,10 @@ class ModuleHelper {
1221
1310
  return bundle;
1222
1311
  }
1223
1312
  validate(icons) {
1224
- const errors = validateOptions(this.options.globalOptions, icons);
1225
- if (errors.length > 0) {
1226
- const lines = errors.map((error) => {
1313
+ let hasErrors = false;
1314
+ const optionErrors = validateOptions(this.options.globalOptions, icons);
1315
+ if (optionErrors.length > 0) {
1316
+ const lines = optionErrors.map((error) => {
1227
1317
  const prefix = error.optionKey ? ` Option "${error.optionKey}": ` : " ";
1228
1318
  return prefix + error.message;
1229
1319
  });
@@ -1231,9 +1321,21 @@ class ModuleHelper {
1231
1321
  `bl\xF6kkli global options validation errors:
1232
1322
  ${lines.join("\n")}`
1233
1323
  );
1234
- return true;
1324
+ hasErrors = true;
1235
1325
  }
1236
- return false;
1326
+ const colorErrors = validateColorOptions(this.options.colorOptions);
1327
+ if (colorErrors.length > 0) {
1328
+ const lines = colorErrors.map((error) => {
1329
+ const prefix = error.optionKey ? ` Option "${error.optionKey}": ` : " ";
1330
+ return prefix + error.message;
1331
+ });
1332
+ this.logger.error(
1333
+ `bl\xF6kkli colorOptions validation errors:
1334
+ ${lines.join("\n")}`
1335
+ );
1336
+ hasErrors = true;
1337
+ }
1338
+ return hasErrors;
1237
1339
  }
1238
1340
  }
1239
1341
 
@@ -2121,12 +2223,20 @@ function mangleClassExpression(expr) {
2121
2223
  }
2122
2224
  return result;
2123
2225
  }
2226
+ const CLASS_BEARING_PROPS = ["button-class", "background-class"];
2124
2227
  function mangleTemplateAndScript(code) {
2125
2228
  let result = code;
2126
2229
  result = result.replace(
2127
2230
  /(?<![-:.])\bclass="([^"]*)"/g,
2128
2231
  (_match, value) => `class="${mangleClassString(value)}"`
2129
2232
  );
2233
+ for (const prop of CLASS_BEARING_PROPS) {
2234
+ const staticAttr = new RegExp(`(?<![:.])\\b${prop}="([^"]*)"`, "g");
2235
+ result = result.replace(
2236
+ staticAttr,
2237
+ (_match, value) => `${prop}="${mangleClassString(value)}"`
2238
+ );
2239
+ }
2130
2240
  result = result.replace(
2131
2241
  /\btw\(\s*(['"])([\s\S]*?)\1\s*\)/g,
2132
2242
  (_match, quote, value) => `tw(${quote}${mangleClassString(value)}${quote})`
@@ -2135,6 +2245,13 @@ function mangleTemplateAndScript(code) {
2135
2245
  /(?::|v-bind:)class="([^"]*)"/g,
2136
2246
  (_match, expr) => `:class="${mangleClassExpression(expr)}"`
2137
2247
  );
2248
+ for (const prop of CLASS_BEARING_PROPS) {
2249
+ const boundAttr = new RegExp(`(:|v-bind:)${prop}="([^"]*)"`, "g");
2250
+ result = result.replace(
2251
+ boundAttr,
2252
+ (_match, prefix, expr) => `${prefix}${prop}="${mangleClassExpression(expr)}"`
2253
+ );
2254
+ }
2138
2255
  return result;
2139
2256
  }
2140
2257
  function withTailwindConfig(cssContent, tailwindConfigPath) {
@@ -2279,6 +2396,19 @@ ${moduleCSS}
2279
2396
  { dependencies: ["module-css"] }
2280
2397
  );
2281
2398
 
2399
+ function buildColorPalette(ctx) {
2400
+ const palette = [];
2401
+ for (const [id, option] of Object.entries(
2402
+ ctx.helper.options.colorOptions || {}
2403
+ )) {
2404
+ if ("shades" in option) {
2405
+ palette.push(`${id}.${option.mainShade}`);
2406
+ } else {
2407
+ palette.push(id);
2408
+ }
2409
+ }
2410
+ return palette;
2411
+ }
2282
2412
  function mapVars(ctx) {
2283
2413
  return {
2284
2414
  itemEntityType: JSON.stringify(
@@ -2289,7 +2419,8 @@ function mapVars(ctx) {
2289
2419
  ),
2290
2420
  fragmentBlockBundle: JSON.stringify(
2291
2421
  ctx.helper.options.fragmentBlockBundle ?? "blokkli_fragment"
2292
- )
2422
+ ),
2423
+ colorPalette: JSON.stringify(buildColorPalette(ctx))
2293
2424
  };
2294
2425
  }
2295
2426
  const config = defineCodeTemplate(
@@ -2302,6 +2433,8 @@ export const itemEntityType = ${vars.itemEntityType}
2302
2433
  export const fromLibraryBlockBundle = ${vars.fromLibraryBlockBundle}
2303
2434
 
2304
2435
  export const fragmentBlockBundle = ${vars.fragmentBlockBundle}
2436
+
2437
+ export const colorPalette = ${vars.colorPalette}
2305
2438
  `;
2306
2439
  },
2307
2440
  (ctx) => {
@@ -2314,6 +2447,15 @@ export declare const itemEntityType: ${vars.itemEntityType}
2314
2447
 
2315
2448
  export declare const fromLibraryBlockBundle: ${vars.fromLibraryBlockBundle}
2316
2449
  export declare const fragmentBlockBundle: ${vars.fragmentBlockBundle}
2450
+
2451
+ /**
2452
+ * Ordered list of canonical default color ids \u2014 one per declared family,
2453
+ * in declaration order. Flat colors appear as bare ids, ramped colors as
2454
+ * \`<id>.<mainShade>\`. Runtime consumers cycle through this to assign
2455
+ * default colors (e.g. dynamic chart series); the runtime composable also
2456
+ * walks it as a fallback cascade when a requested id can't be resolved.
2457
+ */
2458
+ export declare const colorPalette: string[]
2317
2459
  `;
2318
2460
  }
2319
2461
  );
@@ -3176,6 +3318,10 @@ import type { InterfaceLanguage } from '#blokkli-build/translations'
3176
3318
 
3177
3319
  export type ValidColorOption = ${validColorOptions}
3178
3320
 
3321
+ export type GeneratedColorOption =
3322
+ | { label: string; hex: string }
3323
+ | { label: string; shades: Record<string, string>; mainShade: string }
3324
+
3179
3325
  /**
3180
3326
  * Whether the app uses a custom theme.
3181
3327
  */
@@ -3189,7 +3335,7 @@ export declare const themes: Record<string, Theme>
3189
3335
  /**
3190
3336
  * The available color options.
3191
3337
  */
3192
- export declare const colorOptions: Record<ValidColorOption, { hex: string; label: string }>
3338
+ export declare const colorOptions: Record<ValidColorOption, GeneratedColorOption>
3193
3339
 
3194
3340
  /**
3195
3341
  * The default theme.
@@ -4366,14 +4512,21 @@ const module$1 = defineNuxtModule({
4366
4512
  import.meta.url,
4367
4513
  moduleOptions
4368
4514
  );
4369
- const colorOptions = Object.entries(
4515
+ const colorOptions = {};
4516
+ for (const [id, option] of Object.entries(
4370
4517
  helper.options.colorOptions || {}
4371
- ).reduce((acc, entry) => {
4372
- acc[entry[0]] = entry[1].hex;
4373
- return acc;
4374
- }, {});
4518
+ )) {
4519
+ if ("shades" in option) {
4520
+ colorOptions[id] = option.shades[option.mainShade];
4521
+ for (const [shadeId, hex] of Object.entries(option.shades)) {
4522
+ colorOptions[`${id}.${shadeId}`] = hex;
4523
+ }
4524
+ } else {
4525
+ colorOptions[id] = option.hex;
4526
+ }
4527
+ }
4375
4528
  nuxt.options.appConfig.blokkli = {
4376
- // @ts-expect-error The module config type defined a generic Record type, but in userland, this type will automatically contain the actual color keys as properties.
4529
+ // @ts-expect-error generic type vs runtime derived type.
4377
4530
  colorOptions
4378
4531
  };
4379
4532
  const theme = new ThemeData(helper);
@@ -4450,6 +4603,7 @@ const module$1 = defineNuxtModule({
4450
4603
  helper.addComposable("defineBlokkliProvider");
4451
4604
  helper.addComposable("useBlokkli");
4452
4605
  helper.addComposable("useBlokkliHelper");
4606
+ helper.addComposable("useBlokkliRuntimeConfig");
4453
4607
  helper.addAlias(
4454
4608
  "#blokkli/analyzer",
4455
4609
  resolver.resolve("runtime/editor/features/analyze/analyzers")
@@ -7,6 +7,7 @@
7
7
  <script setup>
8
8
  import { computed, useBlokkli } from "#imports";
9
9
  import Markdown from "#blokkli/agent/app/components/Markdown/index.vue";
10
+ import { linkifyBlockUuids } from "#blokkli/agent/app/helpers/linkifyBlockUuids";
10
11
  import { PLACEHOLDER_USER_NAME } from "#blokkli/agent/shared/placeholders";
11
12
  const props = defineProps({
12
13
  id: { type: String, required: true },
@@ -14,11 +15,19 @@ const props = defineProps({
14
15
  type: { type: String, required: true },
15
16
  content: { type: String, required: true }
16
17
  });
17
- const { state } = useBlokkli();
18
- const renderedContent = computed(
19
- () => props.content.replaceAll(
18
+ const { $t, state, blocks, types } = useBlokkli();
19
+ const renderedContent = computed(() => {
20
+ const withName = props.content.replaceAll(
20
21
  PLACEHOLDER_USER_NAME,
21
22
  state.owner.value?.name || ""
22
- )
23
- );
23
+ );
24
+ return linkifyBlockUuids(
25
+ withName,
26
+ (uuid) => {
27
+ const block = blocks.getBlock(uuid);
28
+ return block ? types.getBlockLabel(block.bundle) : null;
29
+ },
30
+ $t("deleted", "deleted")
31
+ );
32
+ });
24
33
  </script>
@@ -6,7 +6,7 @@
6
6
  >
7
7
  <Avatar
8
8
  :deleted="!item.author"
9
- :name="item.author?.name || $t('userDeleted', '[deleted]')"
9
+ :name="item.author?.name || `[${$t('deleted', 'deleted')}]`"
10
10
  :seed="item.author?.id"
11
11
  :image-url="item.author?.imageUrl"
12
12
  />
@@ -15,7 +15,7 @@
15
15
  {{ item.title || $t("agentConversationsUntitled", "Untitled") }}
16
16
  </span>
17
17
  <span class="_bk_text-xs _bk_text-mono-600 _bk_truncate _bk_flex _bk_gap-2">
18
- <span>{{ item.author?.name || $t("userDeleted", "[deleted]") }}</span>
18
+ <span>{{ item.author?.name || `[${$t("deleted", "deleted")}]` }}</span>
19
19
  <span v-if="item.host?.label" class="_bk_truncate">
20
20
  · {{ item.host.label }}
21
21
  </span>
@@ -24,12 +24,12 @@
24
24
  <span class="_bk_text-xs _bk_text-mono-500 _bk_flex _bk_items-center _bk_gap-5 _bk_mt-3">
25
25
  <Avatar
26
26
  :deleted="!item.author"
27
- :name="item.author?.name || $t('userDeleted', '[deleted]')"
27
+ :name="item.author?.name || `[${$t('deleted', 'deleted')}]`"
28
28
  :seed="item.author?.id"
29
29
  :image-url="item.author?.imageUrl"
30
30
  />
31
31
  <span class="_bk_truncate">{{
32
- item.author?.name || $t("userDeleted", "[deleted]")
32
+ item.author?.name || `[${$t("deleted", "deleted")}]`
33
33
  }}</span>
34
34
  <span class="_bk_ml-auto _bk_shrink-0">
35
35
  <RelativeTime :timestamp="item.createdAt" />
@@ -10,11 +10,11 @@
10
10
  <span class="_bk_flex _bk_items-center _bk_gap-5">
11
11
  <Avatar
12
12
  :deleted="!parsed.author"
13
- :name="parsed.author?.name || $t('userDeleted', '[deleted]')"
13
+ :name="parsed.author?.name || `[${$t('deleted', 'deleted')}]`"
14
14
  :seed="parsed.author?.id"
15
15
  :image-url="parsed.author?.imageUrl"
16
16
  />
17
- {{ parsed.author?.name || $t("userDeleted", "[deleted]") }}
17
+ {{ parsed.author?.name || `[${$t("deleted", "deleted")}]` }}
18
18
  </span>
19
19
  <span
20
20
  v-if="parsed.host?.label"
@@ -27,7 +27,9 @@
27
27
  Tool Result ({{ block.tool_use_id }})
28
28
  <span v-if="block.is_error" class="_bk_text-red-dark _bk_ml-5">ERROR</span>
29
29
  </div>
30
- <pre class="bk-agent-transcript-block">{{ block.content }}</pre>
30
+ <pre class="bk-agent-transcript-block">{{
31
+ formatMaybeJson(block.content)
32
+ }}</pre>
31
33
  </template>
32
34
  </div>
33
35
  </template>
@@ -38,4 +40,15 @@
38
40
  defineProps({
39
41
  content: { type: [String, Array], required: true }
40
42
  });
43
+ function formatMaybeJson(value) {
44
+ const trimmed = value.trim();
45
+ if (!trimmed) return value;
46
+ const first = trimmed[0];
47
+ if (first !== "{" && first !== "[") return value;
48
+ try {
49
+ return JSON.stringify(JSON.parse(trimmed), null, 2);
50
+ } catch {
51
+ return value;
52
+ }
53
+ }
41
54
  </script>
@@ -39,6 +39,15 @@
39
39
  <template #post-title>
40
40
  <Pill :text="transcript.messages.length" />
41
41
  </template>
42
+ <template #actions>
43
+ <PanelAction
44
+ :title="
45
+ copiedKey === 'conversation' ? 'Copied!' : 'Copy conversation JSON'
46
+ "
47
+ icon="bk_mdi_content_copy"
48
+ @click="copyConversation"
49
+ />
50
+ </template>
42
51
  <div>
43
52
  <div
44
53
  v-for="(message, i) in transcript.messages"
@@ -69,7 +78,7 @@
69
78
  }}</pre>
70
79
  <template #actions>
71
80
  <PanelAction
72
- :title="copied ? 'Copied!' : 'Copy JSON'"
81
+ :title="copiedKey === 'request' ? 'Copied!' : 'Copy JSON'"
73
82
  icon="bk_mdi_content_copy"
74
83
  @click="copyLastRequest"
75
84
  />
@@ -88,25 +97,34 @@ import { Pill } from "#blokkli/editor/components";
88
97
  const props = defineProps({
89
98
  transcript: { type: Object, required: true }
90
99
  });
91
- const copied = ref(false);
100
+ const copiedKey = ref(null);
92
101
  let copiedTimeout = null;
93
102
  onBeforeUnmount(() => {
94
103
  if (copiedTimeout) {
95
104
  clearTimeout(copiedTimeout);
96
105
  }
97
106
  });
107
+ function flashCopied(key) {
108
+ copiedKey.value = key;
109
+ if (copiedTimeout) {
110
+ clearTimeout(copiedTimeout);
111
+ }
112
+ copiedTimeout = setTimeout(() => {
113
+ copiedKey.value = null;
114
+ copiedTimeout = null;
115
+ }, 2e3);
116
+ }
98
117
  function copyLastRequest() {
99
118
  const json = JSON.stringify(props.transcript.lastRequest, null, 2);
100
- navigator.clipboard.writeText(json).then(() => {
101
- copied.value = true;
102
- if (copiedTimeout) {
103
- clearTimeout(copiedTimeout);
104
- }
105
- copiedTimeout = setTimeout(() => {
106
- copied.value = false;
107
- copiedTimeout = null;
108
- }, 2e3);
109
- });
119
+ navigator.clipboard.writeText(json).then(() => flashCopied("request"));
120
+ }
121
+ function copyConversation() {
122
+ const snapshot = props.transcript.messages.map((m) => ({
123
+ type: m.type,
124
+ content: m.seen
125
+ }));
126
+ const json = JSON.stringify(snapshot, null, 2);
127
+ navigator.clipboard.writeText(json).then(() => flashCopied("conversation"));
110
128
  }
111
129
  </script>
112
130
 
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Replace bare block UUIDs in markdown text with clickable chips. Known UUIDs
3
+ * become `<a class="bk-agent-block-ref" href="#uuid">label</a>`; UUIDs whose
4
+ * block is no longer on the page become a non-clickable
5
+ * `<span class="bk-agent-block-ref-deleted">[<deletedLabel>]</span>`.
6
+ *
7
+ * UUIDs inside fenced or inline code regions and UUIDs already used as a link
8
+ * target (preceded by `#`) are left alone, so existing `[text](#uuid)` links
9
+ * from older conversations pass through unchanged.
10
+ */
11
+ export declare function linkifyBlockUuids(content: string, resolve: (uuid: string) => string | null, deletedLabel: string): string;
@@ -0,0 +1,47 @@
1
+ const UUID_PATTERN = /(?<![\w#-])[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}(?![\w-])/gi;
2
+ const CODE_REGION_PATTERN = /```[\s\S]*?```|`[^`\n]*`/g;
3
+ function escapeHtml(value) {
4
+ return value.replace(/[&<>"']/g, (c) => {
5
+ switch (c) {
6
+ case "&":
7
+ return "&amp;";
8
+ case "<":
9
+ return "&lt;";
10
+ case ">":
11
+ return "&gt;";
12
+ case '"':
13
+ return "&quot;";
14
+ default:
15
+ return "&#39;";
16
+ }
17
+ });
18
+ }
19
+ export function linkifyBlockUuids(content, resolve, deletedLabel) {
20
+ if (!content) return content;
21
+ const parts = [];
22
+ let cursor = 0;
23
+ CODE_REGION_PATTERN.lastIndex = 0;
24
+ let match;
25
+ while ((match = CODE_REGION_PATTERN.exec(content)) !== null) {
26
+ parts.push(
27
+ replaceOutsideCode(
28
+ content.slice(cursor, match.index),
29
+ resolve,
30
+ deletedLabel
31
+ )
32
+ );
33
+ parts.push(match[0]);
34
+ cursor = match.index + match[0].length;
35
+ }
36
+ parts.push(replaceOutsideCode(content.slice(cursor), resolve, deletedLabel));
37
+ return parts.join("");
38
+ }
39
+ function replaceOutsideCode(segment, resolve, deletedLabel) {
40
+ return segment.replace(UUID_PATTERN, (uuid) => {
41
+ const label = resolve(uuid);
42
+ if (label === null) {
43
+ return `<span class="bk-agent-block-ref-deleted">[${escapeHtml(deletedLabel)}]</span>`;
44
+ }
45
+ return `<a class="bk-agent-block-ref" href="#${uuid}">${escapeHtml(label)}</a>`;
46
+ });
47
+ }
@@ -9,6 +9,17 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
9
9
  acceptedCount: number;
10
10
  rejectedByUser: Record<string, Record<string, {
11
11
  reasonForRejection: string;
12
+ partial?: {
13
+ accepted: number;
14
+ total: number;
15
+ rejectedSegments: {
16
+ tag: string;
17
+ beforeHtml: string;
18
+ afterHtml: string;
19
+ status: "deleted" | "matched" | "inserted";
20
+ reasonForRejection: string;
21
+ }[];
22
+ } | undefined;
12
23
  }>>;
13
24
  label: string;
14
25
  agentMessage?: string | undefined;
@@ -19,6 +30,17 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
19
30
  acceptedCount: number;
20
31
  rejectedByUser: Record<string, Record<string, {
21
32
  reasonForRejection: string;
33
+ partial?: {
34
+ accepted: number;
35
+ total: number;
36
+ rejectedSegments: {
37
+ tag: string;
38
+ beforeHtml: string;
39
+ afterHtml: string;
40
+ status: "deleted" | "matched" | "inserted";
41
+ reasonForRejection: string;
42
+ }[];
43
+ } | undefined;
22
44
  }>>;
23
45
  label: string;
24
46
  agentMessage?: string | undefined;