@narumitw/pi-webui 0.29.1 → 0.30.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.
@@ -261,47 +261,49 @@ function App() {
261
261
 
262
262
  function SessionHeader({ model }) {
263
263
  return (
264
- <Container asChild size="3" px={{ initial: "3", sm: "5" }}>
265
- <header className="session-header">
266
- <Box className="session-identity">
267
- <Text as="p" className="eyebrow" color="jade" size="1" weight="bold">
268
- Pi WebUI
269
- </Text>
270
- <Heading as="h1" id="project-name" size="6">
271
- {model.session?.projectName ?? "Connecting…"}
272
- </Heading>
273
- <Text as="p" color="gray" id="session-name" size="2">
274
- {model.session?.name ?? "Current session"}
275
- </Text>
276
- </Box>
277
- <Flex align="center" className="session-controls" gap="2">
278
- <Badge color={connectionColor(model)} id="connection-status" role="status" size="2">
279
- {model.activity === "running" && !model.stale && !model.closed ? (
280
- <Spinner size="1" />
281
- ) : (
282
- <CheckCircledIcon />
283
- )}
284
- {connectionLabel(model)}
285
- </Badge>
286
- <Popover.Root>
287
- <Popover.Trigger asChild>
288
- <Button color="gray" highContrast variant="ghost">
289
- <InfoCircledIcon /> Session details <ChevronDownIcon />
290
- </Button>
291
- </Popover.Trigger>
292
- <Popover.Content align="end" className="session-popover" sideOffset={6}>
293
- <Text as="div" color="gray" size="1" weight="bold">
294
- Working directory
295
- </Text>
296
- <Code id="cwd" size="1" variant="ghost">
297
- {model.session?.cwd ?? ""}
298
- </Code>
299
- <Popover.Arrow className="popover-arrow" />
300
- </Popover.Content>
301
- </Popover.Root>
264
+ <header className="session-header">
265
+ <Container size="3" px={{ initial: "3", sm: "5" }}>
266
+ <Flex className="session-header-content">
267
+ <Box className="session-identity">
268
+ <Text as="p" className="eyebrow" color="jade" size="1" weight="bold">
269
+ Pi WebUI
270
+ </Text>
271
+ <Heading as="h1" id="project-name" size="6">
272
+ {model.session?.projectName ?? "Connecting…"}
273
+ </Heading>
274
+ <Text as="p" color="gray" id="session-name" size="2">
275
+ {model.session?.name ?? "Current session"}
276
+ </Text>
277
+ </Box>
278
+ <Flex align="center" className="session-controls" gap="2">
279
+ <Badge color={connectionColor(model)} id="connection-status" role="status" size="2">
280
+ {model.activity === "running" && !model.stale && !model.closed ? (
281
+ <Spinner size="1" />
282
+ ) : (
283
+ <CheckCircledIcon />
284
+ )}
285
+ {connectionLabel(model)}
286
+ </Badge>
287
+ <Popover.Root>
288
+ <Popover.Trigger asChild>
289
+ <Button color="gray" highContrast variant="ghost">
290
+ <InfoCircledIcon /> Session details <ChevronDownIcon />
291
+ </Button>
292
+ </Popover.Trigger>
293
+ <Popover.Content align="end" className="session-popover" sideOffset={6}>
294
+ <Text as="div" color="gray" size="1" weight="bold">
295
+ Working directory
296
+ </Text>
297
+ <Code id="cwd" size="1" variant="ghost">
298
+ {model.session?.cwd ?? "—"}
299
+ </Code>
300
+ <Popover.Arrow className="popover-arrow" />
301
+ </Popover.Content>
302
+ </Popover.Root>
303
+ </Flex>
302
304
  </Flex>
303
- </header>
304
- </Container>
305
+ </Container>
306
+ </header>
305
307
  );
306
308
  }
307
309
 
@@ -103,24 +103,26 @@ export function ImagePreviewDialog({ image, onOpenChange, revision }) {
103
103
 
104
104
  export function PageFooter() {
105
105
  return (
106
- <Container asChild size="3" px={{ initial: "3", sm: "5" }}>
107
- <footer className="page-footer">
108
- <Separator size="4" />
109
- <Collapsible.Root>
110
- <Collapsible.Trigger asChild>
111
- <Button color="gray" variant="ghost">
112
- <EyeOpenIcon /> Privacy and limitations{" "}
113
- <ChevronDownIcon className="disclosure-icon" />
114
- </Button>
115
- </Collapsible.Trigger>
116
- <Collapsible.Content>
117
- <Text as="p" className="page-footer-copy" color="gray" size="2">
118
- This loopback page reflects semantic Pi messages, not terminal pixels. Data stays in
119
- this live Pi process and browser tab. Thinking is collapsed by default.
120
- </Text>
121
- </Collapsible.Content>
122
- </Collapsible.Root>
123
- </footer>
124
- </Container>
106
+ <footer className="page-footer">
107
+ <Container size="3" px={{ initial: "3", sm: "5" }}>
108
+ <div className="page-footer-content">
109
+ <Separator size="4" />
110
+ <Collapsible.Root>
111
+ <Collapsible.Trigger asChild>
112
+ <Button color="gray" variant="ghost">
113
+ <EyeOpenIcon /> Privacy and limitations{" "}
114
+ <ChevronDownIcon className="disclosure-icon" />
115
+ </Button>
116
+ </Collapsible.Trigger>
117
+ <Collapsible.Content>
118
+ <Text as="p" className="page-footer-copy" color="gray" size="2">
119
+ This loopback page reflects semantic Pi messages, not terminal pixels. Data stays in
120
+ this live Pi process and browser tab. Thinking is collapsed by default.
121
+ </Text>
122
+ </Collapsible.Content>
123
+ </Collapsible.Root>
124
+ </div>
125
+ </Container>
126
+ </footer>
125
127
  );
126
128
  }
@@ -54,12 +54,15 @@ label,
54
54
  }
55
55
 
56
56
  .session-header {
57
+ border-bottom: 1px solid var(--gray-a6);
58
+ }
59
+
60
+ .session-header-content {
57
61
  display: flex;
58
62
  align-items: flex-end;
59
63
  justify-content: space-between;
60
64
  gap: var(--space-5);
61
65
  padding-block: var(--space-5) var(--space-4);
62
- border-bottom: 1px solid var(--gray-a6);
63
66
  }
64
67
 
65
68
  .session-identity {
@@ -461,11 +464,11 @@ pre {
461
464
  object-fit: contain;
462
465
  }
463
466
 
464
- footer {
467
+ .page-footer {
465
468
  padding-block: 0 var(--space-6);
466
469
  }
467
470
 
468
- footer > .rt-Separator {
471
+ .page-footer-content > .rt-Separator {
469
472
  margin-bottom: var(--space-3);
470
473
  }
471
474
 
@@ -507,7 +510,7 @@ footer > .rt-Separator {
507
510
  }
508
511
 
509
512
  @media (max-width: 640px) {
510
- .session-header {
513
+ .session-header-content {
511
514
  align-items: flex-start;
512
515
  padding-top: var(--space-4);
513
516
  }
@@ -1,10 +1,14 @@
1
1
  export function withStableKeys(values) {
2
- const occurrences = new Map();
3
- return values.map((value) => {
4
- const signature = JSON.stringify(value);
5
- const occurrence = occurrences.get(signature) ?? 0;
6
- occurrences.set(signature, occurrence + 1);
7
- return { key: `${signature}:${occurrence}`, value };
2
+ return values.map((value, index) => {
3
+ const type =
4
+ value && typeof value === "object" && typeof value.type === "string" ? value.type : "item";
5
+ const id =
6
+ value &&
7
+ typeof value === "object" &&
8
+ (typeof value.id === "string" || typeof value.id === "number")
9
+ ? value.id
10
+ : undefined;
11
+ return { key: id === undefined ? `${type}:index:${index}` : `${type}:id:${id}`, value };
8
12
  });
9
13
  }
10
14