+
+
+
+
+
diff --git a/packages/graphics-components/src/components/BlogPost/utils.ts b/packages/graphics-components/src/components/BlogPost/utils.ts
new file mode 100644
index 0000000..7934a0b
--- /dev/null
+++ b/packages/graphics-components/src/components/BlogPost/utils.ts
@@ -0,0 +1,9 @@
+/**
+ * Converts a date string to a short date format.
+ * @param d - The date string to be converted.
+ * @returns The short date format string, or empty string if missing or invalid (avoids throwing on `new Date('').toISOString()`).
+ */
+export const getShortDate = (d: string) => {
+ if (!d || Number.isNaN(Date.parse(d))) return '';
+ return new Date(d).toISOString().split('T')[0];
+};
diff --git a/packages/graphics-components/src/components/BlogTOC/BlogTOC.mdx b/packages/graphics-components/src/components/BlogTOC/BlogTOC.mdx
new file mode 100644
index 0000000..2abd80a
--- /dev/null
+++ b/packages/graphics-components/src/components/BlogTOC/BlogTOC.mdx
@@ -0,0 +1,42 @@
+import { Meta, Canvas } from '@storybook/blocks';
+
+import * as BlogTOCStories from './BlogTOC.stories.svelte';
+
+
+
+# BlogTOC
+
+The `BlogTOC` component renders a collapsible table of contents for a graphics blog page, listing all posts sorted chronologically. It only renders when there are two or more posts.
+
+```svelte
+
+
+
+```
+
+The `base` prop should be set to your SvelteKit `base` path (e.g. `"/graphics"`) so that post links resolve correctly.
+
+Each post in the `posts` array must have:
+
+- `title` — the display title
+- `slugTitle` — used to generate the anchor link; **do not change after publishing**
+- `publishTime` — an ISO datetime string used for sorting and the dateline
+
+
diff --git a/packages/graphics-components/src/components/BlogTOC/BlogTOC.stories.svelte b/packages/graphics-components/src/components/BlogTOC/BlogTOC.stories.svelte
new file mode 100644
index 0000000..e2b9c6d
--- /dev/null
+++ b/packages/graphics-components/src/components/BlogTOC/BlogTOC.stories.svelte
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/graphics-components/src/components/BlogTOC/BlogTOC.svelte b/packages/graphics-components/src/components/BlogTOC/BlogTOC.svelte
new file mode 100644
index 0000000..7dc25b1
--- /dev/null
+++ b/packages/graphics-components/src/components/BlogTOC/BlogTOC.svelte
@@ -0,0 +1,275 @@
+
+
+{#if contents.length > 1}
+
+
+
+
+
diff --git a/packages/graphics-components/src/components/Byline/Byline.svelte b/packages/graphics-components/src/components/Byline/Byline.svelte
index c67cb91..1d722e2 100644
--- a/packages/graphics-components/src/components/Byline/Byline.svelte
+++ b/packages/graphics-components/src/components/Byline/Byline.svelte
@@ -13,7 +13,7 @@
/**
* Publish time as a datetime string.
*/
- publishTime: string;
+ publishTime?: string;
/**
* Update time as a datetime string.
*/
@@ -52,7 +52,7 @@
let {
authors = [],
- publishTime,
+ publishTime = '',
updateTime,
align = 'auto',
id = '',
diff --git a/packages/graphics-components/src/components/ClockWall/Clock.svelte b/packages/graphics-components/src/components/ClockWall/Clock.svelte
new file mode 100644
index 0000000..11c75c3
--- /dev/null
+++ b/packages/graphics-components/src/components/ClockWall/Clock.svelte
@@ -0,0 +1,264 @@
+
+
+
+ {#if showClock}
+
+ {/if}
+
+
+ {name}
+
+
+ {time}
+
+
+
+
+
diff --git a/packages/graphics-components/src/components/ClockWall/ClockWall.mdx b/packages/graphics-components/src/components/ClockWall/ClockWall.mdx
new file mode 100644
index 0000000..a005021
--- /dev/null
+++ b/packages/graphics-components/src/components/ClockWall/ClockWall.mdx
@@ -0,0 +1,27 @@
+import { Meta, Canvas } from '@storybook/blocks';
+
+import * as ClockWallStories from './ClockWall.stories.svelte';
+
+
+
+# ClockWall
+
+The `ClockWall` component displays a row of analog clocks for different cities and timezones. Use it paired with the overall headline of a graphics blog page to show the time of multiple cities involved in a breaking news event.
+
+Use the [IANA tz database](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) to find valid `tzIdentifier` strings.
+
+```svelte
+
+
+
+```
+
+
diff --git a/packages/graphics-components/src/components/ClockWall/ClockWall.stories.svelte b/packages/graphics-components/src/components/ClockWall/ClockWall.stories.svelte
new file mode 100644
index 0000000..328ffd5
--- /dev/null
+++ b/packages/graphics-components/src/components/ClockWall/ClockWall.stories.svelte
@@ -0,0 +1,21 @@
+
+
+
diff --git a/packages/graphics-components/src/components/ClockWall/ClockWall.svelte b/packages/graphics-components/src/components/ClockWall/ClockWall.svelte
new file mode 100644
index 0000000..d9f3ddd
--- /dev/null
+++ b/packages/graphics-components/src/components/ClockWall/ClockWall.svelte
@@ -0,0 +1,61 @@
+
+
+
+
+ {#each cities as city (city.tzIdentifier)}
+
+ {/each}
+
+
+
+
diff --git a/packages/graphics-components/src/components/KinesisLogo/KinesisLogo.mdx b/packages/graphics-components/src/components/KinesisLogo/KinesisLogo.mdx
new file mode 100644
index 0000000..83bdafd
--- /dev/null
+++ b/packages/graphics-components/src/components/KinesisLogo/KinesisLogo.mdx
@@ -0,0 +1,19 @@
+import { Meta, Canvas } from '@storybook/blocks';
+
+import * as KinesisLogoStories from './KinesisLogo.stories.svelte';
+
+
+
+# KinesisLogo
+
+The `KinesisLogo` component contains the official Kinesis logo.
+
+```svelte
+
+
+
+```
+
+
diff --git a/packages/graphics-components/src/components/KinesisLogo/KinesisLogo.stories.svelte b/packages/graphics-components/src/components/KinesisLogo/KinesisLogo.stories.svelte
new file mode 100644
index 0000000..1d14157
--- /dev/null
+++ b/packages/graphics-components/src/components/KinesisLogo/KinesisLogo.stories.svelte
@@ -0,0 +1,14 @@
+
+
+
diff --git a/packages/graphics-components/src/components/KinesisLogo/KinesisLogo.svelte b/packages/graphics-components/src/components/KinesisLogo/KinesisLogo.svelte
new file mode 100644
index 0000000..52f527b
--- /dev/null
+++ b/packages/graphics-components/src/components/KinesisLogo/KinesisLogo.svelte
@@ -0,0 +1,140 @@
+
+
+
+
+
+
diff --git a/packages/graphics-components/src/components/TileMap/TileMap.mdx b/packages/graphics-components/src/components/TileMap/TileMap.mdx
index cee4dbf..4057a4b 100644
--- a/packages/graphics-components/src/components/TileMap/TileMap.mdx
+++ b/packages/graphics-components/src/components/TileMap/TileMap.mdx
@@ -53,13 +53,16 @@ Disable interaction for static maps:
Use the `TileMapLayer` component to add GeoJSON data to your map. You can pass GeoJSON data directly or fetch it from a URL. Layer rendering order will directly correspond to the order in which you add the layers in the code.
+> **Note for TypeScript users:** When passing GeoJSON data objects, you'll need to type cast them using `as GeoJSON` to ensure TypeScript recognizes the correct type. This provides better type safety and error messages. See examples below.
+
### Basic example with local data
```svelte
-