Skip to content

@allmaps/ui

UI components and functions for Allmaps.

New shared controls

The shadcn-svelte-based Select is available alongside the existing Allmaps Select:

<script>
import * as Select from '@allmaps/ui/select'
const transformations = [
{ value: 'annotation', label: 'From annotation' },
{ value: 'thinPlateSpline', label: 'Thin plate spline' }
]
let transformation = $state('annotation')
</script>
<label for="transformation" id="transformation-label">Transformation</label>
<Select.Root type="single" items={transformations} bind:value={transformation}>
<Select.Trigger id="transformation" aria-labelledby="transformation-label">
<Select.Value placeholder="Choose a transformation" />
</Select.Trigger>
<Select.Content>
{#each transformations as option (option.value)}
<Select.Item value={option.value} label={option.label} />
{/each}
</Select.Content>
</Select.Root>

The original import { Select } from '@allmaps/ui' is unchanged. The new entry point follows shadcn-svelte’s composable API, uses Bits UI for behavior and Phosphor icons, and imports its own CSS. It does not require an app to scan the package for Tailwind classes. See the source and license.

One Allmaps theme

src/lib/css/ui.css is the single source for the new controls’ colors, fonts, control heights, radius, focus ring and shadows. It defines semantic --allmaps-ui-* variables and supports both .dark and Starlight’s data-theme="dark" on the document root. The Select entry point imports it automatically. Other consumers can import @allmaps/ui/css/ui.css explicitly. Font families use Geograph and DM Mono; import @allmaps/ui/css/fonts.css if the app does not already load those fonts.

Override tokens on the document root, after importing the theme, so controls and menus portaled to the document body share the same values:

:root {
--allmaps-ui-primary: #ff56ba;
--allmaps-ui-ring: var(--allmaps-ui-primary);
--allmaps-ui-radius: 0.375rem;
--allmaps-ui-font-sans: 'Geograph', system-ui, sans-serif;
}

Add future shadcn-based components under src/lib/components/ui/, use the shared .allmaps-ui typography class and theme tokens, and export each through its own entry point. To use Tailwind 4’s semantic shadcn utilities, import the theme into the app’s Tailwind stylesheet as well:

@import 'tailwindcss';
@import '@allmaps/ui/css/ui.css';

Names such as bg-popover, text-foreground, border-input, ring-ring and rounded-md then use the same Allmaps variables. Component CSS lives in the components layer, allowing utility classes and app overrides to customize it. Keep theme values out of individual components. There is no global reset or change to the existing components’ styles.

Screenshot

Display a saved WebP screenshot in a simplified browser window:

<script>
import { Screenshot } from '@allmaps/ui'
</script>
<Screenshot
url="https://viewer.allmaps.org/"
slug="viewer"
alt="Allmaps Viewer"
/>

The component renders a <div>, without a link. url only controls the page to capture. Wrap the component in your own <a> to link anywhere you choose:

<a href="https://allmaps.org/">
<Screenshot
url="https://viewer.allmaps.org/"
slug="viewer"
alt="Allmaps Viewer"
/>
</a>

The default image URL is https://files.allmaps.org/screenshots/viewer/v1.webp. The component renders a normal image with SVG browser controls, intrinsic dimensions, and lazy loading. Use loading="eager" for a prominent image above the fold. src overrides the image URL for local previews or existing images, and filesBaseUrl selects another file host. class styles the outer container. The frame exposes --screenshot-border, --screenshot-background, and --screenshot-color CSS custom properties.

Optional capture props are version (default 1), viewport (1440 × 900 at 2× density), waitForSelector, waitForRender (observe Allmaps tile loading and wait for stable pixels), and delay (milliseconds, default 1000). Slugs use lowercase words separated by hyphens. Increment version to publish a new image URL without replacing images used by older pages.

The component works without a collector and never captures or uploads images from a visitor’s browser. With the optional Vite plugin, instances register their resolved capture settings during prerendering. In dev, the plugin previews local captures automatically and falls back to the published URL when missing. See the screenshot tool for collection, local capture, and publishing through the Assets CLI.

SVG highlights

Pass captured geometry and a highlights array of target names to draw SVG outlines over the clean image. The overlay is included in server-rendered HTML and scales with the image, independently of the capture’s device pixel ratio. Use highlightPadding (default 4) and the --screenshot-highlight-color and --screenshot-highlight-width CSS variables to style it. Different instances can highlight different targets from one capture without recapturing the image.

The capture props steps and targets prepare the page and record named element bounds. Geometry is a separate versioned JSON asset, supplied by your server loader or imported alongside the image. The screenshot tool provides loadScreenshotGeometry to validate local image/metadata pairs. See its preparation and highlight documentation for the complete workflow and examples.

Interactive map examples

Use MapExample from @allmaps/ui/examples to switch between MapLibre, Leaflet and OpenLayers. It defaults to MapLibre; pass library="Leaflet" or library="OpenLayers" to select another initial library. The annotation URL, opacity, transformation and initial-view settings are preserved when switching, and the source code and install command update for the selected library. Switching disposes the old map and creates a new one. Each library, Allmaps plugin and stylesheet loads only when selected and the map is near the viewport; loaded modules are reused when switching back.

Use an interactive map and its JavaScript example together:

<script>
import { MapLibreExample } from '@allmaps/ui/examples/maplibre'
</script>
<MapLibreExample
annotationUrl="https://annotations.allmaps.org/maps/1bfb1eb4198e7240@c83337fa4b8051c9"
opacity={1}
transformation="annotation"
height={400}
/>

The read-only, highlighted source code reflects the map controls. Opacity and transformation apply immediately. Choose a map from the examples dropdown to load it immediately, or submit an annotation URL with Load or Enter. Changing the transformation preserves the current view. Reset view fits the map to its extent again. The default transformation, annotation, preserves each map’s transformation. You can override it with polynomial1, helmert or thinPlateSpline, or choose From annotation to restore it. Default opacity and transformation setters are omitted from the copied code. Copy code gives you a short, standalone example using the selected settings. The map container markup and install command appear in separate highlighted HTML and Bash blocks below the JavaScript. Each block has its own Copy code button.

Initial view offers three approaches, with Fit after loading as the default:

  • Fit after loading adds the annotation, then fits the map to its extent.
  • Known bounds uses fixed coordinates to position the map before loading the annotation. The example fills in these coordinates for the selected map. You can also supply a bounds prop as [west, south, east, north].
  • WarpedMapList loads the annotation into a list first, calculates its extent, and shares the list with the layer. The install command adds @allmaps/render.

Use viewMode="fit", viewMode="bounds" or viewMode="list" to choose the initial option. Switching it recreates the map and updates the source code. IIIF HTTP and network failures appear with a retry option, and stalled image requests time out.

The dropdown includes Saigon, Amsterdam, Vienna, and Britain and Ireland. Pass an examples array of { label, annotationUrl } objects to use your own list, or examples={[]} to hide the dropdown.

Separate entry points also export LeafletExample from @allmaps/ui/examples/leaflet and OpenLayersExample from @allmaps/ui/examples/openlayers. Each component dynamically imports its own mapping library when the map approaches the viewport. The components and copied examples use a bundler such as Vite for CSS imports and the MapLibre worker.

In Astro MDX, import the component and add client:visible. The same components work directly in Svelte apps. They use the site’s Starlight theme variables when available and otherwise have their own defaults.

Latest maps

Import the latest georeferenced maps component through its dedicated entry point:

<script lang="ts">
import { Latest } from '@allmaps/ui/latest'
</script>
<Latest count={12} showProperties={false} showUrls={false} />
Prop Default Description
count 100 Number of maps requested when the component mounts.
showHeader false Show the heading and map/error counts.
showProperties true Show control point count, mask point count, and area.
showUrls true Show links to the editor, viewer, and annotation.

The component fetches maps from https://api.allmaps.org/maps in the browser. It owns its loading state and per-map error presentation. Consuming apps provide routing and global styles. Use the Allmaps Tailwind theme and scan all UI output, including the nested Latest components:

import { theme } from '@allmaps/tailwind'
export default {
content: [
'./src/**/*.{html,js,svelte,ts}',
'./node_modules/@allmaps/ui/dist/**/*.{html,js,svelte,ts}'
],
theme
}

From the repository root, pnpm --filter @allmaps/ui run prepack packages the library without building its demo app. pnpm --filter @allmaps/ui run watch updates the package while developing a consumer. The Latest app and homepage both consume @allmaps/ui/latest.

License

MIT; see LICENSE.md.