@agent-native/creative-context 0.7.18 → 0.7.19-nightly-20260902002038

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.
@@ -1,3 +1,7 @@
1
+ import { useT } from "@agent-native/core/client/i18n";
2
+ import { docsUrl } from "@agent-native/core/shared";
3
+ import { cn } from "@agent-native/toolkit";
4
+ import { ShareDisclosureSection } from "@agent-native/toolkit/sharing";
1
5
  import {
2
6
  Badge,
3
7
  Button,
@@ -10,23 +14,11 @@ import {
10
14
  SelectValue,
11
15
  Sheet,
12
16
  SheetContent,
13
- SheetDescription,
14
17
  SheetHeader,
15
18
  SheetTitle,
16
- Tabs,
17
- TabsContent,
18
- TabsList,
19
- TabsTrigger,
20
19
  Textarea,
21
20
  } from "@agent-native/toolkit/ui";
22
- import {
23
- IconCheck,
24
- IconFileText,
25
- IconLink,
26
- IconPlus,
27
- IconShieldCheck,
28
- IconX,
29
- } from "@tabler/icons-react";
21
+ import { IconCheck, IconFileText, IconPlus, IconX } from "@tabler/icons-react";
30
22
  import { useEffect, useState } from "react";
31
23
 
32
24
  import {
@@ -38,7 +30,6 @@ import {
38
30
  useManageCreativeContext,
39
31
  type CreativeContextMembership,
40
32
  type CreativeContextMembershipRank,
41
- type CreativeContextPolicy,
42
33
  type CreativeContextSummary,
43
34
  } from "./actions.js";
44
35
 
@@ -83,6 +74,7 @@ export function normalizeCreativeContextResources(
83
74
  }
84
75
 
85
76
  const VISIBILITY_RANK = { private: 0, org: 1, public: 2 } as const;
77
+ type CreativeContextTranslate = ReturnType<typeof useT>;
86
78
 
87
79
  export function requiresBroaderPublication(
88
80
  resource: CreativeContextResourceDescriptor,
@@ -111,27 +103,6 @@ export function creativeContextSafePreviewUrl(url: string | undefined) {
111
103
  }
112
104
  }
113
105
 
114
- function policyCopy(policy: CreativeContextPolicy) {
115
- switch (policy) {
116
- case "review":
117
- return "New resources wait for reviewer approval before they are reused.";
118
- case "admins-only":
119
- return "Only administrators can approve or remove resources.";
120
- default:
121
- return "New resources are published after submission.";
122
- }
123
- }
124
-
125
- function formatResourceTimestamp(value: string | undefined) {
126
- if (!value) return null;
127
- const date = new Date(value);
128
- if (!Number.isFinite(date.getTime())) return null;
129
- return new Intl.DateTimeFormat(undefined, {
130
- dateStyle: "medium",
131
- timeStyle: "short",
132
- }).format(date);
133
- }
134
-
135
106
  function ResourcePreview({
136
107
  resource,
137
108
  }: {
@@ -143,13 +114,13 @@ function ResourcePreview({
143
114
  <img
144
115
  src={imageUrl}
145
116
  alt={resource.preview?.alt ?? ""}
146
- className="size-11 rounded-md border border-border object-cover"
117
+ className="size-9 rounded-md border border-border object-cover"
147
118
  />
148
119
  );
149
120
  }
150
121
  return (
151
- <div className="flex size-11 items-center justify-center rounded-md border border-border bg-muted text-muted-foreground">
152
- <IconFileText className="size-5" />
122
+ <div className="flex size-9 items-center justify-center rounded-md border border-border bg-muted text-muted-foreground">
123
+ <IconFileText className="size-4" />
153
124
  </div>
154
125
  );
155
126
  }
@@ -210,6 +181,7 @@ export async function submitCreativeContextResources({
210
181
 
211
182
  function MembershipRow({
212
183
  membership,
184
+ t,
213
185
  updateAvailable,
214
186
  canReview,
215
187
  canWithdraw,
@@ -218,6 +190,7 @@ function MembershipRow({
218
190
  onAction,
219
191
  }: {
220
192
  membership: CreativeContextMembership;
193
+ t: CreativeContextTranslate;
221
194
  updateAvailable: boolean;
222
195
  canReview: boolean;
223
196
  canWithdraw: boolean;
@@ -228,45 +201,71 @@ function MembershipRow({
228
201
  ) => void;
229
202
  }) {
230
203
  const pending = Boolean(membership.pendingSubmissionId);
204
+ const rankLabel = {
205
+ canonical: t("creativeContext.share.canonical", {
206
+ defaultValue: "Canonical",
207
+ }),
208
+ exemplar: t("creativeContext.exemplar"),
209
+ normal: t("creativeContext.share.reference", {
210
+ defaultValue: "Reference",
211
+ }),
212
+ }[membership.rank];
231
213
  return (
232
- <article className="flex flex-wrap items-center justify-between gap-3 rounded-md border border-border p-3">
233
- <div>
234
- <p className="text-sm font-medium">
235
- {pending ? "Pending resource" : "Published resource"}
236
- </p>
237
- <p className="mt-0.5 text-xs text-muted-foreground">
238
- {membership.rank}{" "}
239
- {membership.purpose ? `· ${membership.purpose}` : ""}
240
- </p>
214
+ <article className="flex flex-wrap items-center justify-between gap-2 border-t border-border/60 py-2.5 first:border-t-0">
215
+ <div className="flex min-w-0 items-center gap-2">
216
+ <Badge variant={pending ? "outline" : "secondary"} className="shrink-0">
217
+ {pending
218
+ ? t("creativeContext.share.pendingResource", {
219
+ defaultValue: "Pending resource",
220
+ })
221
+ : t("creativeContext.share.publishedResource", {
222
+ defaultValue: "Published resource",
223
+ })}
224
+ </Badge>
225
+ <span className="min-w-0 truncate text-xs text-muted-foreground">
226
+ {membership.purpose ?? rankLabel}
227
+ </span>
228
+ {updateAvailable ? (
229
+ <span className="shrink-0 text-xs text-muted-foreground">
230
+ {t("creativeContext.updateAvailable")}
231
+ </span>
232
+ ) : null}
241
233
  </div>
242
- <div className="flex flex-wrap gap-2">
234
+ <div className="flex flex-wrap justify-end gap-1">
243
235
  {pending ? (
244
- <Badge variant="outline">Pending review</Badge>
236
+ <Badge variant="outline">
237
+ {t("creativeContext.share.pendingReview", {
238
+ defaultValue: "Pending review",
239
+ })}
240
+ </Badge>
245
241
  ) : (
246
- <Badge variant="secondary">Published</Badge>
242
+ <span className="sr-only">
243
+ {t("creativeContext.share.published", {
244
+ defaultValue: "Published",
245
+ })}
246
+ </span>
247
247
  )}
248
- {updateAvailable ? (
249
- <Badge variant="outline">Update available</Badge>
250
- ) : null}
251
248
  {pending && canWithdraw ? (
252
249
  <Button
253
250
  type="button"
254
251
  variant="outline"
255
252
  size="sm"
253
+ className="h-8 px-2 text-xs"
256
254
  disabled={busy}
257
255
  onClick={() => onAction("withdraw")}
258
256
  >
259
- Withdraw
257
+ {t("creativeContext.share.withdraw", { defaultValue: "Withdraw" })}
260
258
  </Button>
261
259
  ) : null}
262
260
  {pending && canReview ? (
263
261
  <Button
264
262
  type="button"
265
263
  size="sm"
264
+ className="h-8 px-2 text-xs"
266
265
  disabled={busy}
267
266
  onClick={() => onAction("approve")}
268
267
  >
269
- <IconCheck /> Approve
268
+ <IconCheck /> {t("creativeContext.approve")}
270
269
  </Button>
271
270
  ) : null}
272
271
  {pending && canReview ? (
@@ -274,10 +273,13 @@ function MembershipRow({
274
273
  type="button"
275
274
  size="sm"
276
275
  variant="outline"
276
+ className="h-8 px-2 text-xs"
277
277
  disabled={busy}
278
278
  onClick={() => onAction("request-changes")}
279
279
  >
280
- Request changes
280
+ {t("creativeContext.share.requestChanges", {
281
+ defaultValue: "Request changes",
282
+ })}
281
283
  </Button>
282
284
  ) : null}
283
285
  {canRemove ? (
@@ -285,10 +287,12 @@ function MembershipRow({
285
287
  type="button"
286
288
  size="sm"
287
289
  variant="ghost"
290
+ className="h-8 px-2 text-xs"
288
291
  disabled={busy}
289
292
  onClick={() => onAction("remove")}
290
293
  >
291
- <IconX /> Remove
294
+ <IconX />{" "}
295
+ {t("creativeContext.share.remove", { defaultValue: "Remove" })}
292
296
  </Button>
293
297
  ) : null}
294
298
  </div>
@@ -299,16 +303,24 @@ function MembershipRow({
299
303
  function ContextSelect({
300
304
  contexts,
301
305
  contextId,
306
+ t,
302
307
  onValueChange,
308
+ disabled = false,
303
309
  }: {
304
310
  contexts: CreativeContextSummary[];
305
311
  contextId: string;
312
+ t: CreativeContextTranslate;
306
313
  onValueChange: (value: string) => void;
314
+ disabled?: boolean;
307
315
  }) {
308
316
  return (
309
317
  <Select value={contextId} onValueChange={onValueChange}>
310
- <SelectTrigger>
311
- <SelectValue placeholder="Choose a context" />
318
+ <SelectTrigger className="w-full" disabled={disabled}>
319
+ <SelectValue
320
+ placeholder={t("creativeContext.share.chooseContext", {
321
+ defaultValue: "Choose a context",
322
+ })}
323
+ />
312
324
  </SelectTrigger>
313
325
  {/* This tab is embedded inside ShareButton's high z-index popover
314
326
  (see z-[100010]+ overrides in design/content/slides toolbars).
@@ -332,6 +344,7 @@ export function CreativeContextShareTab({
332
344
  resources,
333
345
  className,
334
346
  }: CreativeContextShareTabProps) {
347
+ const t = useT();
335
348
  const contextsQuery = useCreativeContexts();
336
349
  const manageContext = useManageCreativeContext();
337
350
  const manageMembership = useManageContextMembership();
@@ -341,7 +354,6 @@ export function CreativeContextShareTab({
341
354
  resources,
342
355
  );
343
356
  const primaryResource = selectedResources[0];
344
- const updatedAt = formatResourceTimestamp(primaryResource?.updatedAt);
345
357
  const [contextId, setContextId] = useState("");
346
358
  const membershipsQuery = useContextMemberships(
347
359
  contextId ? { contextId } : null,
@@ -360,7 +372,9 @@ export function CreativeContextShareTab({
360
372
  useState(false);
361
373
  const busy = manageContext.isPending || manageMembership.isPending;
362
374
  const selectedContext = contexts.find((context) => context.id === contextId);
363
- const canCreateContext = contexts.some((context) => context.access.canAdmin);
375
+ const canCreateContext =
376
+ contextsQuery.data?.canCreateContext === true &&
377
+ contexts.some((context) => context.access.canAdmin);
364
378
  const needsBroaderPublicationConfirmation = selectedResources.some((item) =>
365
379
  requiresBroaderPublication(item, selectedContext),
366
380
  );
@@ -398,12 +412,28 @@ export function CreativeContextShareTab({
398
412
  setConfirmedBroaderPublication(false);
399
413
  setSubmitSummary(
400
414
  result.failed
401
- ? `${result.submitted} submitted; ${result.failed} could not be submitted.`
402
- : `${result.submitted} ${result.submitted === 1 ? "resource" : "resources"} submitted.`,
415
+ ? t("creativeContext.share.partialSubmission", {
416
+ submitted: result.submitted,
417
+ failed: result.failed,
418
+ defaultValue:
419
+ "{{submitted}} submitted; {{failed}} could not be submitted.",
420
+ })
421
+ : t(
422
+ result.submitted === 1
423
+ ? "creativeContext.share.resourceSubmitted"
424
+ : "creativeContext.share.resourcesSubmitted",
425
+ {
426
+ count: result.submitted,
427
+ defaultValue:
428
+ result.submitted === 1
429
+ ? "{{count}} resource submitted."
430
+ : "{{count}} resources submitted.",
431
+ },
432
+ ),
403
433
  );
404
434
  await refresh();
405
435
  } catch {
406
- setError("Could not submit this resource to the selected context.");
436
+ setError(t("creativeContext.submitUpdateFailed"));
407
437
  }
408
438
  }
409
439
 
@@ -421,7 +451,7 @@ export function CreativeContextShareTab({
421
451
  await contextsQuery.refetch();
422
452
  if (result.context?.id) setContextId(result.context.id);
423
453
  } catch {
424
- setError("Could not create a context.");
454
+ setError(t("creativeContext.saveFailed"));
425
455
  }
426
456
  }
427
457
 
@@ -439,97 +469,83 @@ export function CreativeContextShareTab({
439
469
  });
440
470
  await refresh();
441
471
  } catch {
442
- setError("Could not update this context membership.");
472
+ setError(t("creativeContext.saveFailed"));
443
473
  }
444
474
  }
445
475
 
446
476
  return (
447
- <section className={className} aria-label="Creative context">
448
- <div className="flex items-start gap-3 border-b border-border/70 pb-4">
449
- {primaryResource ? (
477
+ <section
478
+ className={cn("space-y-3", className)}
479
+ aria-label={t("creativeContext.share.title", {
480
+ defaultValue: "Creative context",
481
+ })}
482
+ >
483
+ {primaryResource ? (
484
+ <div className="flex min-w-0 items-center gap-2 border-b border-border/70 pb-3">
450
485
  <ResourcePreview resource={primaryResource} />
451
- ) : null}
452
- <div className="min-w-0">
453
- <p className="truncate text-sm font-medium">
486
+ <p className="min-w-0 truncate text-sm font-medium">
454
487
  {selectedResources.length === 1
455
- ? primaryResource?.title
456
- : `${selectedResources.length} selected resources`}
488
+ ? primaryResource.title
489
+ : t("creativeContext.share.selectedResources", {
490
+ count: selectedResources.length,
491
+ defaultValue: "{{count}} selected resources",
492
+ })}
457
493
  </p>
458
- <p className="mt-0.5 text-xs text-muted-foreground">
459
- {selectedResources.length === 1
460
- ? (primaryResource?.preview?.label ??
461
- primaryResource?.resourceType)
462
- : "Each resource is submitted separately"}
463
- </p>
464
- {selectedResources.length === 1 && updatedAt ? (
465
- <p className="mt-0.5 text-xs text-muted-foreground">
466
- Current version · {updatedAt}
467
- </p>
468
- ) : null}
469
494
  </div>
470
- </div>
471
- <Tabs defaultValue="contexts" className="mt-4">
472
- <TabsList className="w-full justify-start">
473
- <TabsTrigger value="contexts">Contexts</TabsTrigger>
474
- <TabsTrigger value="policy">Policy</TabsTrigger>
475
- </TabsList>
476
- <TabsContent value="contexts" className="space-y-3">
477
- <ContextSelect
478
- contexts={contexts}
479
- contextId={contextId}
480
- onValueChange={setContextId}
481
- />
482
- {selectedContext ? (
483
- <p className="text-xs text-muted-foreground">
484
- {selectedContext.description ||
485
- `${selectedContext.memberCount} published resources`}{" "}
486
- · {policyCopy(selectedContext.approvalPolicy)}
487
- </p>
488
- ) : (
489
- <p className="text-sm text-muted-foreground">
490
- No contexts are available yet.
491
- </p>
492
- )}
493
- {contextId && selectedResources.length === 1 ? (
494
- <div className="space-y-2">
495
- {memberships.map((membership) => (
496
- <MembershipRow
497
- key={membership.id}
498
- membership={membership}
499
- updateAvailable={Boolean(
500
- primaryResource?.updatedAt &&
501
- membership.publishedItem?.sourceModifiedAt &&
502
- primaryResource.updatedAt !==
503
- membership.publishedItem.sourceModifiedAt,
504
- )}
505
- canReview={selectedContext?.access.canReview === true}
506
- canWithdraw={
507
- selectedContext?.access.canReview === true ||
508
- selectedContext?.access.canSubmit === true
509
- }
510
- canRemove={selectedContext?.access.canAdmin === true}
511
- busy={busy}
512
- onAction={(operation) => void act(membership.id, operation)}
513
- />
514
- ))}
515
- {!memberships.length && !membershipsQuery.isLoading ? (
516
- <p className="text-sm text-muted-foreground">
517
- This resource has not been submitted to this context.
518
- </p>
519
- ) : null}
520
- </div>
521
- ) : null}
522
- {contextId && selectedResources.length ? (
523
- <div className="rounded-md border border-dashed border-border p-3">
524
- <p className="text-sm font-medium">
525
- {memberships.some((membership) => membership.publishedItem)
526
- ? "Submit update for "
527
- : "Add "}
528
- {selectedResources.length === 1
529
- ? "this resource"
530
- : `${selectedResources.length} resources`}
531
- </p>
532
- <div className="mt-2 grid gap-2 sm:grid-cols-2">
495
+ ) : null}
496
+ {contexts.length ? (
497
+ <ContextSelect
498
+ contexts={contexts}
499
+ contextId={contextId}
500
+ t={t}
501
+ onValueChange={setContextId}
502
+ disabled={busy}
503
+ />
504
+ ) : (
505
+ <p className="text-sm text-muted-foreground">
506
+ {t("creativeContext.share.noContexts", {
507
+ defaultValue: "No contexts are available yet.",
508
+ })}
509
+ </p>
510
+ )}
511
+ {contextId && selectedResources.length === 1 && memberships.length ? (
512
+ <div>
513
+ {memberships.map((membership) => (
514
+ <MembershipRow
515
+ key={membership.id}
516
+ membership={membership}
517
+ t={t}
518
+ updateAvailable={Boolean(
519
+ primaryResource?.updatedAt &&
520
+ membership.publishedItem?.sourceModifiedAt &&
521
+ primaryResource.updatedAt !==
522
+ membership.publishedItem.sourceModifiedAt,
523
+ )}
524
+ canReview={selectedContext?.access.canReview === true}
525
+ canWithdraw={
526
+ selectedContext?.access.canReview === true ||
527
+ selectedContext?.access.canSubmit === true
528
+ }
529
+ canRemove={selectedContext?.access.canAdmin === true}
530
+ busy={busy}
531
+ onAction={(operation) => void act(membership.id, operation)}
532
+ />
533
+ ))}
534
+ </div>
535
+ ) : null}
536
+ {contextId && selectedResources.length ? (
537
+ <div className="border-t border-border/60 pt-3">
538
+ <div className="mb-3 flex items-start gap-2">
539
+ <ShareDisclosureSection
540
+ label={
541
+ memberships.some((membership) => membership.publishedItem)
542
+ ? t("creativeContext.submitUpdate")
543
+ : t("creativeContext.addToContext")
544
+ }
545
+ className="min-w-0 flex-1"
546
+ contentClassName="space-y-2"
547
+ >
548
+ <div className="grid gap-2 sm:grid-cols-2">
533
549
  <Select
534
550
  value={rank}
535
551
  onValueChange={(value) =>
@@ -543,94 +559,114 @@ export function CreativeContextShareTab({
543
559
  data-agent-native-share-overlay=""
544
560
  className="z-[100020]"
545
561
  >
546
- <SelectItem value="canonical">Canonical</SelectItem>
547
- <SelectItem value="exemplar">Exemplar</SelectItem>
548
- <SelectItem value="normal">Reference</SelectItem>
562
+ <SelectItem value="canonical">
563
+ {t("creativeContext.share.canonical", {
564
+ defaultValue: "Canonical",
565
+ })}
566
+ </SelectItem>
567
+ <SelectItem value="exemplar">
568
+ {t("creativeContext.exemplar")}
569
+ </SelectItem>
570
+ <SelectItem value="normal">
571
+ {t("creativeContext.share.reference", {
572
+ defaultValue: "Reference",
573
+ })}
574
+ </SelectItem>
549
575
  </SelectContent>
550
576
  </Select>
551
577
  <Input
552
578
  value={purpose}
553
579
  onChange={(event) => setPurpose(event.target.value)}
554
- placeholder="Purpose"
580
+ placeholder={t("creativeContext.share.purpose", {
581
+ defaultValue: "Purpose",
582
+ })}
555
583
  />
556
584
  </div>
557
585
  <Textarea
558
- className="mt-2"
559
586
  value={note}
560
587
  onChange={(event) => setNote(event.target.value)}
561
- placeholder="Note for reviewers"
588
+ placeholder={t("creativeContext.share.reviewerNote", {
589
+ defaultValue: "Note for reviewers",
590
+ })}
562
591
  rows={2}
563
592
  />
564
- {needsBroaderPublicationConfirmation ? (
565
- <label className="mt-3 flex items-start gap-2 text-xs text-muted-foreground">
566
- <Checkbox
567
- checked={confirmedBroaderPublication}
568
- onCheckedChange={(checked) =>
569
- setConfirmedBroaderPublication(checked === true)
570
- }
571
- />
572
- <span>
573
- This context is shared more broadly than this resource.
574
- Publishing creates a governed copy available to the
575
- context's audience.
576
- </span>
577
- </label>
578
- ) : null}
579
- <Button
580
- type="button"
581
- className="mt-3"
582
- size="sm"
583
- disabled={
584
- busy ||
585
- selectedContext?.access.canSubmit !== true ||
586
- (needsBroaderPublicationConfirmation &&
587
- !confirmedBroaderPublication)
593
+ </ShareDisclosureSection>
594
+ <Button
595
+ type="button"
596
+ size="sm"
597
+ className="shrink-0"
598
+ disabled={
599
+ busy ||
600
+ selectedContext?.access.canSubmit !== true ||
601
+ (needsBroaderPublicationConfirmation &&
602
+ !confirmedBroaderPublication)
603
+ }
604
+ onClick={() => void submit()}
605
+ >
606
+ {t("creativeContext.share.submit", { defaultValue: "Submit" })}
607
+ </Button>
608
+ </div>
609
+ {needsBroaderPublicationConfirmation ? (
610
+ <label className="flex items-start gap-2 text-xs text-muted-foreground">
611
+ <Checkbox
612
+ checked={confirmedBroaderPublication}
613
+ onCheckedChange={(checked) =>
614
+ setConfirmedBroaderPublication(checked === true)
588
615
  }
589
- onClick={() => void submit()}
590
- >
591
- <IconLink /> Submit
592
- </Button>
593
- </div>
594
- ) : null}
595
- {canCreateContext ? (
596
- <div className="flex gap-2 border-t border-border/60 pt-3">
597
- <Input
598
- value={newContextName}
599
- onChange={(event) => setNewContextName(event.target.value)}
600
- placeholder="New context name"
601
616
  />
602
- <Button
603
- type="button"
604
- variant="outline"
605
- size="sm"
606
- disabled={busy || !newContextName.trim()}
607
- onClick={() => void createContext()}
608
- >
609
- <IconPlus /> New
610
- </Button>
611
- </div>
617
+ <span>
618
+ {t("creativeContext.share.broaderPublication", {
619
+ defaultValue:
620
+ "This context is shared more broadly than this resource. Publishing creates a governed copy available to the context's audience.",
621
+ })}
622
+ </span>
623
+ </label>
612
624
  ) : null}
613
- {error ? <p className="text-xs text-destructive">{error}</p> : null}
614
- {submitSummary ? (
615
- <p className="text-xs text-muted-foreground">{submitSummary}</p>
616
- ) : null}
617
- </TabsContent>
618
- <TabsContent
619
- value="policy"
620
- className="space-y-3 text-sm text-muted-foreground"
625
+ </div>
626
+ ) : null}
627
+ {canCreateContext ? (
628
+ <ShareDisclosureSection
629
+ label={t("creativeContext.share.newContextName", {
630
+ defaultValue: "New context name",
631
+ })}
621
632
  >
622
- <div className="flex gap-2 rounded-md border border-border p-3">
623
- <IconShieldCheck className="mt-0.5 size-4 shrink-0" />
624
- <p>
625
- Open contexts publish submitted resources, review contexts wait
626
- for approval, and admins-only contexts require an administrator.
627
- </p>
633
+ <div className="flex gap-2">
634
+ <Input
635
+ value={newContextName}
636
+ onChange={(event) => setNewContextName(event.target.value)}
637
+ placeholder={t("creativeContext.share.newContextName", {
638
+ defaultValue: "New context name",
639
+ })}
640
+ />
641
+ <Button
642
+ type="button"
643
+ variant="outline"
644
+ size="sm"
645
+ disabled={busy || !newContextName.trim()}
646
+ onClick={() => void createContext()}
647
+ >
648
+ <IconPlus />{" "}
649
+ {t("creativeContext.share.new", { defaultValue: "New" })}
650
+ </Button>
628
651
  </div>
629
- {selectedContext ? (
630
- <p>{policyCopy(selectedContext.approvalPolicy)}</p>
631
- ) : null}
632
- </TabsContent>
633
- </Tabs>
652
+ </ShareDisclosureSection>
653
+ ) : null}
654
+ {error ? <p className="text-xs text-destructive">{error}</p> : null}
655
+ {submitSummary ? (
656
+ <p className="text-xs text-muted-foreground">{submitSummary}</p>
657
+ ) : null}
658
+ <a
659
+ href={docsUrl("toolkit-capability-packages", {
660
+ hash: "package-maturity-and-ownership",
661
+ })}
662
+ target="_blank"
663
+ rel="noreferrer"
664
+ className="inline-flex text-xs font-medium text-muted-foreground underline-offset-2 hover:text-foreground hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
665
+ >
666
+ {t("creativeContext.share.documentation", {
667
+ defaultValue: "Creative Context documentation",
668
+ })}
669
+ </a>
634
670
  </section>
635
671
  );
636
672
  }
@@ -645,14 +681,16 @@ export function CreativeContextShareSheet({
645
681
  open: boolean;
646
682
  onOpenChange: (open: boolean) => void;
647
683
  }) {
684
+ const t = useT();
648
685
  return (
649
686
  <Sheet open={open} onOpenChange={onOpenChange}>
650
687
  <SheetContent side="right" className="w-full overflow-y-auto sm:max-w-lg">
651
688
  <SheetHeader>
652
- <SheetTitle>Creative context</SheetTitle>
653
- <SheetDescription>
654
- Place this resource in a governed context for future reuse.
655
- </SheetDescription>
689
+ <SheetTitle>
690
+ {t("creativeContext.share.title", {
691
+ defaultValue: "Creative context",
692
+ })}
693
+ </SheetTitle>
656
694
  </SheetHeader>
657
695
  <CreativeContextShareTab
658
696
  resource={resource}