@messagevisor/catalog 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.html CHANGED
@@ -5,8 +5,8 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <link rel="icon" type="image/png" href="/favicon.png" />
7
7
  <title>Messagevisor Catalog</title>
8
- <script type="module" crossorigin src="/assets/index-BoO0zn_O.js"></script>
9
- <link rel="stylesheet" crossorigin href="/assets/index-Cn0qFwkD.css">
8
+ <script type="module" crossorigin src="/assets/index-OXIn4K-M.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/assets/index-DrsX4U8c.css">
10
10
  </head>
11
11
  <body>
12
12
  <div id="root"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@messagevisor/catalog",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Static catalog UI for Messagevisor projects",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -57,5 +57,5 @@
57
57
  "typescript": "^5.7.2",
58
58
  "vite": "^6.0.7"
59
59
  },
60
- "gitHead": "53cfef1a5ae28724b24226dd3a32ff813b063ce3"
60
+ "gitHead": "62ca354700133c05c4466a4515f415be6f934eb2"
61
61
  }
@@ -8,7 +8,7 @@ export function FieldGrid(props: {
8
8
  {props.fields.map((field) => (
9
9
  <div key={field.label} className={field.fullWidth ? "md:col-span-2" : ""}>
10
10
  <dt className="text-sm font-medium text-muted">{field.label}</dt>
11
- <dd className="mt-1 text-sm">{field.value || "n/a"}</dd>
11
+ <dd className="mt-1 min-w-0 text-sm [overflow-wrap:anywhere]">{field.value || "n/a"}</dd>
12
12
  </div>
13
13
  ))}
14
14
  </dl>
@@ -2,6 +2,7 @@ import { Link } from "react-router-dom";
2
2
  import type { GroupSegment } from "@messagevisor/types";
3
3
 
4
4
  import { Badge } from "../ui/Badge";
5
+ import { EntityKey } from "../ui/EntityKey";
5
6
  import { getEntityRoute } from "../../entityTypes";
6
7
 
7
8
  function SegmentLeaf(props: { segmentKey: string; setKey?: string }) {
@@ -13,7 +14,7 @@ function SegmentLeaf(props: { segmentKey: string; setKey?: string }) {
13
14
  to={getEntityRoute("segment", props.segmentKey, props.setKey)}
14
15
  className="font-semibold text-primary hover:underline"
15
16
  >
16
- {props.segmentKey}
17
+ <EntityKey value={props.segmentKey} className="font-semibold" />
17
18
  </Link>
18
19
  </div>
19
20
  </div>
@@ -2,6 +2,7 @@ import { Link } from "react-router-dom";
2
2
 
3
3
  import type { EntityType } from "../../types";
4
4
  import { getEntityRoute } from "../../entityTypes";
5
+ import { EntityKey } from "../ui/EntityKey";
5
6
 
6
7
  export function UsageLinks(props: { type: EntityType; keys?: string[]; setKey?: string }) {
7
8
  if (!props.keys || props.keys.length === 0) {
@@ -11,7 +12,7 @@ export function UsageLinks(props: { type: EntityType; keys?: string[]; setKey?:
11
12
  return (
12
13
  <ul className="list-inside list-disc space-y-1 text-sm">
13
14
  {props.keys.map((key) => (
14
- <li key={key}>
15
+ <li key={key} className="[overflow-wrap:anywhere]">
15
16
  <Link
16
17
  className="text-primary hover:underline"
17
18
  to={getEntityRoute(
@@ -20,7 +21,7 @@ export function UsageLinks(props: { type: EntityType; keys?: string[]; setKey?:
20
21
  props.setKey,
21
22
  )}
22
23
  >
23
- {key}
24
+ <EntityKey value={key} className="font-medium" />
24
25
  </Link>
25
26
  </li>
26
27
  ))}
@@ -7,6 +7,7 @@ import type { HistoryEntry } from "../../types";
7
7
  import { formatCatalogTimestamp } from "../../utils/formatCatalogTimestamp";
8
8
  import { CATALOG_HISTORY_VISIBLE_ENTITY_LIMIT } from "../../config";
9
9
  import { Button } from "../ui/Button";
10
+ import { EntityKey } from "../ui/EntityKey";
10
11
  import { EmptyState } from "../ui/EmptyState";
11
12
 
12
13
  function HistoryEntryCard(props: { entry: HistoryEntry; setKey?: string; commitUrl?: string }) {
@@ -36,17 +37,17 @@ function HistoryEntryCard(props: { entry: HistoryEntry; setKey?: string; commitU
36
37
  </div>
37
38
  <ul className="mt-3 list-inside list-disc space-y-1 text-sm text-muted">
38
39
  {visibleEntities.map((entity) => (
39
- <li key={`${entity.type}-${entity.key}`}>
40
+ <li key={`${entity.type}-${entity.key}`} className="[overflow-wrap:anywhere]">
40
41
  {entity.type !== "test" ? entityLabels[entity.type].singular : "Test"}{" "}
41
42
  {entity.type !== "test" ? (
42
43
  <Link
43
44
  className="font-medium text-primary hover:underline"
44
45
  to={getEntityRoute(entity.type, entity.key, entity.set || props.setKey)}
45
46
  >
46
- {entity.key}
47
+ <EntityKey value={entity.key} className="font-medium" />
47
48
  </Link>
48
49
  ) : (
49
- entity.key
50
+ <EntityKey value={entity.key} className="font-medium" />
50
51
  )}
51
52
  </li>
52
53
  ))}
@@ -1,11 +1,21 @@
1
1
  import type { ReactNode } from "react";
2
2
 
3
- export function PageHeader(props: { title: string; description?: ReactNode; actions?: ReactNode }) {
3
+ export function PageHeader(props: {
4
+ title: ReactNode;
5
+ description?: ReactNode;
6
+ actions?: ReactNode;
7
+ }) {
4
8
  return (
5
9
  <div className="mb-6 flex flex-col justify-between gap-4 border-b border-border px-6 pb-4 pt-8 md:flex-row md:items-start">
6
10
  <div className="min-w-0 flex-1">
7
- <h1 className="break-words text-3xl font-black text-text">{props.title}</h1>
8
- {props.description && <div className="mt-2 text-sm text-muted">{props.description}</div>}
11
+ <h1 className="min-w-0 text-3xl font-black text-text [overflow-wrap:anywhere]">
12
+ {props.title}
13
+ </h1>
14
+ {props.description && (
15
+ <div className="mt-2 min-w-0 text-sm text-muted [overflow-wrap:anywhere]">
16
+ {props.description}
17
+ </div>
18
+ )}
9
19
  </div>
10
20
  {props.actions ? <div className="shrink-0">{props.actions}</div> : null}
11
21
  </div>
@@ -9,6 +9,7 @@ import { Badge } from "../ui/Badge";
9
9
  import { EmptyState } from "../ui/EmptyState";
10
10
  import { Input } from "../ui/Input";
11
11
  import { Button } from "../ui/Button";
12
+ import { EntityKey } from "../ui/EntityKey";
12
13
  import { CATALOG_LIST_INITIAL_LIMIT } from "../../config";
13
14
  import type { ParsedQuery } from "../../utils/searchQuery";
14
15
  import { parseQuery } from "../../utils/searchQuery";
@@ -409,7 +410,7 @@ export function EntityList(props: {
409
410
  <div className="min-w-0 flex-1">
410
411
  <div className="flex flex-col justify-between gap-2 md:flex-row md:items-start">
411
412
  <div className="min-w-0">
412
- <div className="font-bold text-primary">{entity.key}</div>
413
+ <EntityKey value={entity.key} className="text-sm font-semibold text-primary" />
413
414
  <div className="mt-1 truncate text-sm text-muted">
414
415
  {entity.description || "No description"}
415
416
  </div>
@@ -0,0 +1,20 @@
1
+ export function EntityKey(props: { value: string; className?: string }) {
2
+ const parts = props.value.split(".");
3
+
4
+ return (
5
+ <span
6
+ className={["inline leading-snug [overflow-wrap:anywhere]", props.className || ""].join(" ")}
7
+ >
8
+ {parts.map((part, index) => (
9
+ <span key={`${part}-${index}`}>
10
+ {part}
11
+ {index < parts.length - 1 ? (
12
+ <>
13
+ .<wbr />
14
+ </>
15
+ ) : null}
16
+ </span>
17
+ ))}
18
+ </span>
19
+ );
20
+ }
@@ -30,6 +30,7 @@ import { PageHeader } from "../components/layout/PageHeader";
30
30
  import { Tabs } from "../components/layout/Tabs";
31
31
  import { Badge } from "../components/ui/Badge";
32
32
  import { CodeBlock } from "../components/ui/CodeBlock";
33
+ import { EntityKey } from "../components/ui/EntityKey";
33
34
  import { LabelValueBadge } from "../components/ui/LabelValueBadge";
34
35
  import { EmptyState } from "../components/ui/EmptyState";
35
36
  import { Input } from "../components/ui/Input";
@@ -1195,7 +1196,15 @@ export function EntityDetailPage() {
1195
1196
  return (
1196
1197
  <div>
1197
1198
  <PageHeader
1198
- title={`${entityLabels[type].singular}: ${detail.key}`}
1199
+ title={
1200
+ <span className="flex min-w-0 flex-wrap items-baseline gap-x-2 gap-y-1">
1201
+ <span className="whitespace-nowrap">{entityLabels[type].singular}:</span>
1202
+ <EntityKey
1203
+ value={detail.key}
1204
+ className="min-w-0 text-[1.45rem] font-extrabold leading-tight"
1205
+ />
1206
+ </span>
1207
+ }
1199
1208
  description={
1200
1209
  <div className="flex flex-wrap items-center gap-2">
1201
1210
  {entity.archived && <Badge tone="danger">archived</Badge>}
@@ -1638,7 +1647,7 @@ function MessageTranslationOverridesDetails(props: {
1638
1647
  to={`${getEntityRoute("message", props.messageKey, props.setKey)}/overrides#${key}`}
1639
1648
  className="text-sm font-semibold text-primary hover:underline"
1640
1649
  >
1641
- {key}
1650
+ <EntityKey value={key} className="font-semibold" />
1642
1651
  </Link>
1643
1652
  {row.source === "inherited" && row.from && (
1644
1653
  <LabelValueBadge
@@ -1800,8 +1809,8 @@ export function MessageOverridesTab() {
1800
1809
  <section key={override.key} className="space-y-4">
1801
1810
  <div className="space-y-3">
1802
1811
  <div className="group flex items-center gap-2">
1803
- <h2 id={override.key} className="font-semibold">
1804
- {override.key}
1812
+ <h2 id={override.key} className="font-semibold [overflow-wrap:anywhere]">
1813
+ <EntityKey value={override.key} className="font-semibold" />
1805
1814
  </h2>
1806
1815
  <ExamplePermalink targetId={override.key} />
1807
1816
  </div>
@@ -3141,7 +3150,7 @@ export function LocaleDuplicatesTab() {
3141
3150
  <td className="min-w-0 border-b border-border px-3 py-2">
3142
3151
  <Link
3143
3152
  to={getEntityRoute("message", messageKey, setKey)}
3144
- className="font-medium text-primary hover:underline"
3153
+ className="font-medium text-primary [overflow-wrap:anywhere] hover:underline"
3145
3154
  >
3146
3155
  <ExamplesSearchHighlight
3147
3156
  text={messageKey}