diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 0089a99e..adac5da7 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -20,7 +20,9 @@ "Bash(cat:*)", "Read(//Users/masashi/.gradle/caches/**)", "Bash(xargs jar tf:*)", - "Bash(npm run build:*)" + "Bash(npm run build:*)", + "WebFetch(domain:medium.com)", + "WebSearch" ], "deny": [], "ask": [] diff --git a/.gitignore b/.gitignore index 5b4a4c30..18ddf103 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,6 @@ compose-map-story/ slides/ *.secrets act.env +.gradle-user-home +arcgis-heatmap-issue.txt +session.txt diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index d07b0e7e..00000000 --- a/CLAUDE.md +++ /dev/null @@ -1,103 +0,0 @@ -# CLAUDE.md - -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. - -## Project Overview - -MapConductor Android SDK is a unified mapping library that provides a common API for multiple map providers (Google Maps, Mapbox, HERE, ArcGIS). The project follows a multi-module architecture with a core module and provider-specific implementations. - -## Build and Development Commands - -### Building the Project -```bash -./gradlew build -``` - -### Linting and Code Style -The project uses KtLint for code formatting. Run lint checks and auto-formatting: -```bash -./gradlew allLintChecks -``` - -This command runs `ktlintFormat` and `lint` for all modules defined in `projects.properties`. - -### Running Tests -```bash -./gradlew test -``` - -### Running Specific Module Tests -```bash -./gradlew :mapconductor-core:test -./gradlew :mapconductor-for-googlemaps:test -``` - -## Module Architecture - -### Core Module (`mapconductor-core`) -- **Purpose**: Contains shared abstractions, base classes, and common functionality -- **Key Components**: - - `MapViewController`: Abstract controller interface for all map providers - - `MapViewBase`: Generic Compose-based map view component - - `MarkerManager`, `CircleManager`, `PolylineOverlayManager`: Feature management - - `HexGeocell`: Spatial indexing for efficient marker clustering - - Projection utilities (`WebMercator`, `WGS84`) - -### Provider-Specific Modules -Each map provider has its own module that implements the core abstractions: - -- **`mapconductor-for-googlemaps`**: Google Maps implementation -- **`mapconductor-for-mapbox`**: Mapbox implementation -- **`mapconductor-for-here`**: HERE Maps implementation -- **`mapconductor-for-arcgis`**: ArcGIS implementation - -### Supporting Modules -- **`mapconductor-icons`**: Reusable marker icon components -- **`example-app`**: Demo application showcasing all map providers - -## Key Design Patterns - -### Generic Type System -The architecture uses extensive generics to maintain type safety while supporting multiple map SDKs: -```kotlin -interface MapViewController -class MapViewBase -``` - -### State Management -- Uses Kotlin StateFlow for reactive state management -- Debounced updates (100ms) to prevent excessive recomposition -- `MapViewState` manages initialization lifecycle - -### Overlay Management -- Separate managers for markers, circles, and polylines -- Renderer pattern for provider-specific drawing logic -- Spatial indexing with hexagonal cells for performance - -## Configuration Files - -### `projects.properties` -Defines all modules included in the build. Update this file when adding new modules. - -### `secrets.properties` -Contains API keys for map providers. Must be obtained from the credentials repository. - -### `gradle/libs.versions.toml` -Centralized dependency management using Gradle version catalogs. - -## Feature Implementation Status - -Currently working on Polyline support across all providers. Check the README.md table for current feature completion status. - -## Development Guidelines - -- Follow existing naming conventions and package structure -- New features should be implemented in the core module first, then in each provider module -- Use the existing renderer pattern for drawing operations -- Maintain type safety with appropriate generic constraints -- Provider-specific code should be isolated to respective modules - -## Testing -- Unit tests in each module's `src/test` directory -- Instrumented tests in `src/androidTest` directories -- Use existing test patterns and mock objects where appropriate \ No newline at end of file diff --git a/README.md b/README.md index 70abf994..8ba4547e 100644 --- a/README.md +++ b/README.md @@ -25,11 +25,11 @@ A unified mapping library that provides a common API for multiple map providers ### Key Components -- **MapViewController**: Abstract controller interface for all map providers +- **MapViewControllerInterface**: Abstract controller interface for all map providers - **MapViewBase**: Generic Compose-based map view component - **Overlay Managers**: Separate managers for markers, circles, polylines, and polygons -- **Projection Utilities**: WebMercator and WGS84 coordinate transformations -- **HexGeocell**: Spatial indexing system for performance optimization +- **ProjectionInterface Utilities**: WebMercator and WGS84 coordinate transformations +- **HexGeocellInterface**: Spatial indexing system for performance optimization ## Quick Start diff --git a/Sources/MapConductorForGoogleMaps/marker/GoogleMapMarkerTilingOptions.swift b/Sources/MapConductorForGoogleMaps/marker/GoogleMapMarkerTilingOptions.swift new file mode 100644 index 00000000..4ac7f1ed --- /dev/null +++ b/Sources/MapConductorForGoogleMaps/marker/GoogleMapMarkerTilingOptions.swift @@ -0,0 +1,17 @@ +import Foundation + +public struct GoogleMapMarkerTilingOptions: Equatable, Hashable, Sendable { + public var enabled: Bool + public var minMarkerCount: Int + + public init( + enabled: Bool = true, + minMarkerCount: Int = 2000 + ) { + self.enabled = enabled + self.minMarkerCount = minMarkerCount + } + + public static let disabled: GoogleMapMarkerTilingOptions = .init(enabled: false) +} + diff --git a/Sources/MapConductorForGoogleMaps/marker/GoogleMapTiledMarkerLayer.swift b/Sources/MapConductorForGoogleMaps/marker/GoogleMapTiledMarkerLayer.swift new file mode 100644 index 00000000..c1c53d66 --- /dev/null +++ b/Sources/MapConductorForGoogleMaps/marker/GoogleMapTiledMarkerLayer.swift @@ -0,0 +1,197 @@ +import CoreGraphics +import GoogleMaps +import UIKit + +internal final class GoogleMapTiledMarkerLayer: GMSTileLayer { + internal struct RenderMarker { + let id: String + let latitude: Double + let longitude: Double + let visible: Bool + let image: CGImage + let anchorX: CGFloat + let anchorY: CGFloat + let drawWidth: Double + let drawHeight: Double + } + + private let tileSizePx: Int + private let renderScale: Int + private let lock = NSLock() + + private var markersById: [String: RenderMarker] = [:] + private var indexedZoom: Int = -1 + private var tileToMarkerIds: [UInt64: [String]] = [:] + + init( + mapView: GMSMapView, + tileSizePx: Int = 256, + zIndex: Int32 = 0 + ) { + self.tileSizePx = max(1, tileSizePx) + self.renderScale = min(2, max(1, Int(round(UIScreen.main.scale)))) + super.init() + tileSize = self.tileSizePx + self.zIndex = zIndex + map = mapView + } + + func setMarkers( + _ markers: [String: RenderMarker], + zoom: Int + ) { + lock.lock() + markersById = markers + rebuildIndexLocked(zoom: zoom) + lock.unlock() + clearTileCache() + } + + func setZoom(_ zoom: Int) { + lock.lock() + if zoom == indexedZoom { + lock.unlock() + return + } + rebuildIndexLocked(zoom: zoom) + lock.unlock() + clearTileCache() + } + + func remove() { + map = nil + } + + override func tileFor(x: UInt, y: UInt, zoom: UInt) -> UIImage? { + let requestedZoom = Int(zoom) + let worldTileCount = 1 << requestedZoom + if Int(y) < 0 || Int(y) >= worldTileCount { return nil } + + let normalizedX = normalizeTileX(Int(x), worldTileCount: worldTileCount) + let key = tileKey(x: normalizedX, y: Int(y)) + + lock.lock() + let zoomIndex = (requestedZoom == indexedZoom) ? tileToMarkerIds : [:] + let ids = zoomIndex[key] ?? [] + let markers = markersById + lock.unlock() + + if ids.isEmpty { return nil } + + let renderTileSize = tileSizePx * renderScale + let format = UIGraphicsImageRendererFormat.default() + format.scale = 1 + format.opaque = false + + let renderImage = UIGraphicsImageRenderer(size: CGSize(width: renderTileSize, height: renderTileSize), format: format).image { ctx in + let context = ctx.cgContext + context.setAllowsAntialiasing(true) + context.setShouldAntialias(true) + context.interpolationQuality = .high + if renderScale != 1 { + context.scaleBy(x: CGFloat(renderScale), y: CGFloat(renderScale)) + } + + let worldPixelSize = Double(worldTileCount * tileSizePx) + let tileOriginX = Double(normalizedX * tileSizePx) + let tileOriginY = Double(Int(y) * tileSizePx) + + for id in ids { + guard let marker = markers[id] else { continue } + if !marker.visible { continue } + let pixel = mercatorPixel(latitude: marker.latitude, longitude: marker.longitude, worldPixelSize: worldPixelSize) + let localX = pixel.x - tileOriginX + let localY = pixel.y - tileOriginY + + let left = Double(localX) - Double(marker.anchorX) * marker.drawWidth + let top = Double(localY) - Double(marker.anchorY) * marker.drawHeight + let rect = CGRect(x: left, y: top, width: marker.drawWidth, height: marker.drawHeight) + context.draw(marker.image, in: rect) + } + } + + if renderScale == 1 { return renderImage } + + let finalImage = UIGraphicsImageRenderer(size: CGSize(width: tileSizePx, height: tileSizePx), format: format).image { ctx in + ctx.cgContext.interpolationQuality = .high + renderImage.draw(in: CGRect(x: 0, y: 0, width: tileSizePx, height: tileSizePx)) + } + return finalImage + } + + private struct Pixel { + let x: Double + let y: Double + } + + private func mercatorPixel( + latitude: Double, + longitude: Double, + worldPixelSize: Double + ) -> Pixel { + let clampedLatitude = min(85.05112878, max(-85.05112878, latitude)) + let sinLatitude = min(0.9999, max(-0.9999, sin(clampedLatitude * .pi / 180.0))) + let x = (longitude + 180.0) / 360.0 + let y = 0.5 - log((1.0 + sinLatitude) / (1.0 - sinLatitude)) / (4.0 * .pi) + + let pixelX = normalizePixel(x * worldPixelSize, worldPixelSize: worldPixelSize) + let pixelY = min(worldPixelSize - 1.0, max(0.0, y * worldPixelSize)) + return Pixel(x: pixelX, y: pixelY) + } + + private func normalizePixel(_ pixel: Double, worldPixelSize: Double) -> Double { + let wrapped = pixel.truncatingRemainder(dividingBy: worldPixelSize) + return wrapped < 0 ? wrapped + worldPixelSize : wrapped + } + + private func normalizeTileX(_ x: Int, worldTileCount: Int) -> Int { + let wrapped = x % worldTileCount + return wrapped < 0 ? wrapped + worldTileCount : wrapped + } + + private func tileKey(x: Int, y: Int) -> UInt64 { + (UInt64(bitPattern: Int64(x)) << 32) ^ (UInt64(bitPattern: Int64(y)) & 0xffffffff) + } + + private func rebuildIndexLocked(zoom: Int) { + if markersById.isEmpty { + indexedZoom = zoom + tileToMarkerIds = [:] + return + } + + let worldTileCount = 1 << zoom + let worldPixelSize = Double(worldTileCount * tileSizePx) + var tiles: [UInt64: [String]] = [:] + tiles.reserveCapacity(min(4096, markersById.count)) + + for marker in markersById.values { + if !marker.visible { continue } + let pixel = mercatorPixel(latitude: marker.latitude, longitude: marker.longitude, worldPixelSize: worldPixelSize) + let left = pixel.x - Double(marker.anchorX) * marker.drawWidth + let top = pixel.y - Double(marker.anchorY) * marker.drawHeight + let right = left + marker.drawWidth + let bottom = top + marker.drawHeight + + let minTileX = Int(floor(left / Double(tileSizePx))) + let maxTileX = Int(floor((right - 1.0) / Double(tileSizePx))) + let minTileY = Int(floor(top / Double(tileSizePx))) + let maxTileY = Int(floor((bottom - 1.0) / Double(tileSizePx))) + + if minTileY >= worldTileCount || maxTileY < 0 { continue } + for tileY in minTileY...maxTileY { + if tileY < 0 || tileY >= worldTileCount { continue } + for tileX in minTileX...maxTileX { + let normalizedX = normalizeTileX(tileX, worldTileCount: worldTileCount) + let key = tileKey(x: normalizedX, y: tileY) + if tiles[key] == nil { tiles[key] = [] } + tiles[key]?.append(marker.id) + } + } + } + + indexedZoom = zoom + tileToMarkerIds = tiles + } +} + diff --git a/build.gradle.kts b/build.gradle.kts index ec8e752c..d9a9b212 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,9 +1,10 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. +// Top-level build file where you can add configuration options common to all sub-projects/modules. import java.util.Properties plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.kotlin.android) apply false alias(libs.plugins.kotlin.compose) apply false + alias(libs.plugins.kotlin.jvm) apply false alias(libs.plugins.android.library) apply false alias(libs.plugins.jlleitschuh.ktlint) apply false id("com.gradleup.nmcp") version "0.0.8" @@ -60,7 +61,7 @@ tasks.register("allLintChecks") { val lintTasks = modules .filter { it != "mapconductor-bom" } - .map { module -> + .flatMap { module -> listOf(":$module:ktlintFormat", ":$module:lint") } @@ -121,3 +122,4 @@ nmcp { // All publications from all subprojects will be published } } + diff --git a/docs/.claude/settings.local.json b/docs/.claude/settings.local.json index 41b1dd9f..c50564ad 100644 --- a/docs/.claude/settings.local.json +++ b/docs/.claude/settings.local.json @@ -1,21 +1,7 @@ { "permissions": { "allow": [ - "Bash(npm run build:*)", - "Bash(taskkill:*)", - "Bash(find:*)", - "Bash(npm create:*)", - "Bash(npm install)", - "Bash(npm view:*)", - "Bash(npm search:*)", - "Bash(cat:*)", - "WebFetch(domain:localhost)", - "Bash(curl:*)", - "Bash(for f in src/content/docs/*.md src/content/docs/**/*.md)", - "Bash(do if [ -f \"$f\" ])", - "Bash(fi)", - "Bash(done)", - "Bash(for f in src/content/docs/ja/**/*.md src/content/docs/ja/*.md)" + "Bash(./gradlew:*)" ], "deny": [], "ask": [] diff --git a/docs/astro.config.mjs b/docs/astro.config.ts similarity index 81% rename from docs/astro.config.mjs rename to docs/astro.config.ts index 24c53a95..f9732a04 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.ts @@ -1,15 +1,17 @@ -// @ts-check import { defineConfig } from 'astro/config'; import starlight from '@astrojs/starlight'; import starlightMermaid from '@pasqal-io/starlight-client-mermaid'; import { fileURLToPath } from 'node:url'; import remarkVersionPlaceholder from './src/remark/versionPlaceholder.ts'; +import versionPlaceholderPlugin from './src/vite/versionPlaceholderPlugin.ts'; +import postBuildIntegration from './src/astro/postBuildIntegration.ts'; // https://astro.build/config export default defineConfig({ site: 'https://mapconductor.com', outDir: 'dist', integrations: [ + postBuildIntegration(), starlight({ title: 'MapConductor', description: 'A unified map SDK for mobile developers', @@ -47,8 +49,6 @@ export default defineConfig({ { slug: 'introduction' }, { slug: 'get-started' }, { slug: 'modules' }, - { slug: 'sdk-version-compatibility' }, - { slug: 'provider-compatibility' }, ], }, { @@ -90,9 +90,7 @@ export default defineConfig({ { slug: 'core/geopoint' }, { slug: 'core/georectbounds' }, { slug: 'core/mapcameraposition' }, - { slug: 'core/mapviewholder' }, { slug: 'core/marker-icons' }, - { slug: 'core/marker-animation' }, { slug: 'core/spherical-utilities' }, { slug: 'core/zoom-levels' }, ], @@ -110,16 +108,39 @@ export default defineConfig({ { slug: 'states/groundimage-state' }, ], }, + // { + // label: 'Events', + // translations: { + // ja: 'イベント', + // }, + // items: [ + // { slug: 'event/onMapLoaded' }, + // // { slug: 'event/onCameraMoveStart' }, + // // { slug: 'event/onCameraMove' }, + // // { slug: 'event/onCameraMoveEnd' }, + // ], + // }, + { + label: 'MapViewHolder', + items: [ + { slug: 'mapviewholder' }, + { slug: 'mapviewholder/googlemaps' }, + { slug: 'mapviewholder/mapbox' }, + { slug: 'mapviewholder/here-maps' }, + { slug: 'mapviewholder/arcgis' }, + { slug: 'mapviewholder/maplibre' }, + ], + }, { - label: 'API Reference', + label: 'ArcGIS Integration', translations: { - ja: 'API リファレンス', + ja: 'ArcGISポータルとの連携', }, items: [ - { slug: 'api/initialization' }, - { slug: 'api/event-handlers' }, + { slug: 'cloud/arcgis/arcgis-oauth-hybrid-initialize' }, ], }, + // { // label: 'Examples', // translations: { @@ -175,6 +196,9 @@ export default defineConfig({ }), ], vite: { + plugins: [ + versionPlaceholderPlugin(), + ], resolve: { // Match Starlight docs behavior so `~/` points to `src/` alias: { diff --git a/docs/package-lock.json b/docs/package-lock.json index fe736f56..45f42f4b 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -17,6 +17,7 @@ "unist-util-visit": "^5.0.0" }, "devDependencies": { + "openai": "^4.0.0", "typescript": "^5.9.3" } }, @@ -2330,6 +2331,17 @@ "undici-types": "~7.16.0" } }, + "node_modules/@types/node-fetch": { + "version": "2.6.13", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.13.tgz", + "integrity": "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.4" + } + }, "node_modules/@types/sax": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz", @@ -2358,6 +2370,19 @@ "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", "license": "ISC" }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, "node_modules/acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", @@ -2379,6 +2404,19 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/ansi-align": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", @@ -2665,6 +2703,13 @@ "astro": "^4.0.0-beta || ^5.0.0-beta || ^3.3.0" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, "node_modules/await-lock": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/await-lock/-/await-lock-2.2.2.tgz", @@ -2778,6 +2823,20 @@ "base64-js": "^1.1.2" } }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/camelcase": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz", @@ -2948,6 +3007,19 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/comma-separated-tokens": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", @@ -3670,6 +3742,16 @@ "robust-predicates": "^3.0.2" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -3844,6 +3926,21 @@ "node": ">=4" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/emoji-regex": { "version": "10.6.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", @@ -3862,12 +3959,61 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-module-lexer": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", "license": "MIT" }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/esast-util-from-estree": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz", @@ -4044,6 +4190,16 @@ "@types/estree": "^1.0.0" } }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/eventemitter3": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", @@ -4133,6 +4289,44 @@ "unicode-trie": "^2.0.0" } }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data-encoder": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", + "dev": true, + "license": "MIT" + }, + "node_modules/formdata-node": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "node-domexception": "1.0.0", + "web-streams-polyfill": "4.0.0-beta.3" + }, + "engines": { + "node": ">= 12.20" + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -4147,6 +4341,16 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/get-east-asian-width": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", @@ -4159,6 +4363,45 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/github-slugger": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", @@ -4177,6 +4420,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -4206,6 +4462,48 @@ "integrity": "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==", "license": "MIT" }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/hast-util-embedded": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/hast-util-embedded/-/hast-util-embedded-3.0.0.tgz", @@ -4632,6 +4930,16 @@ "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", "license": "BSD-2-Clause" }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, "node_modules/i18next": { "version": "23.16.8", "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.16.8.tgz", @@ -5031,6 +5339,16 @@ "node": ">= 20" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/mdast-util-definitions": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-6.0.0.tgz", @@ -6124,6 +6442,29 @@ ], "license": "MIT" }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/mlly": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", @@ -6214,6 +6555,48 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-fetch-native": { "version": "1.6.7", "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", @@ -6281,6 +6664,54 @@ "regex-recursion": "^6.0.2" } }, + "node_modules/openai": { + "version": "4.104.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.104.0.tgz", + "integrity": "sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7" + }, + "bin": { + "openai": "bin/cli" + }, + "peerDependencies": { + "ws": "^8.18.0", + "zod": "^3.23.8" + }, + "peerDependenciesMeta": { + "ws": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/openai/node_modules/@types/node": { + "version": "18.19.130", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz", + "integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/openai/node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true, + "license": "MIT" + }, "node_modules/p-limit": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-6.2.0.tgz", @@ -7342,6 +7773,13 @@ "tlds": "bin.js" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, "node_modules/trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", @@ -7990,6 +8428,34 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which-pm-runs": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz", diff --git a/docs/package.json b/docs/package.json index 85896409..750b8725 100644 --- a/docs/package.json +++ b/docs/package.json @@ -10,7 +10,8 @@ "start:es": "astro dev --host", "build": "astro build", "preview": "astro preview", - "astro": "astro" + "astro": "astro", + "translate:docs": "node ./scripts/translate-docs.mjs" }, "dependencies": { "@astrojs/starlight": "^0.36.2", @@ -22,6 +23,7 @@ "unist-util-visit": "^5.0.0" }, "devDependencies": { - "typescript": "^5.9.3" + "typescript": "^5.9.3", + "openai": "^4.0.0" } } diff --git a/docs/pnpm-lock.yaml b/docs/pnpm-lock.yaml new file mode 100644 index 00000000..2c0866cc --- /dev/null +++ b/docs/pnpm-lock.yaml @@ -0,0 +1,5680 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@astrojs/starlight': + specifier: ^0.36.2 + version: 0.36.3(astro@5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3)) + '@pasqal-io/starlight-client-mermaid': + specifier: ^0.1.0 + version: 0.1.0(@astrojs/markdown-remark@6.3.10)(@astrojs/starlight@0.36.3(astro@5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3))) + astro: + specifier: ^5.16.0 + version: 5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3) + astro-embed: + specifier: ^0.9.2 + version: 0.9.2(astro@5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3)) + mermaid: + specifier: ^11.12.1 + version: 11.12.2 + sharp: + specifier: ^0.34.5 + version: 0.34.5 + unist-util-visit: + specifier: ^5.0.0 + version: 5.0.0 + devDependencies: + openai: + specifier: ^4.0.0 + version: 4.104.0(zod@3.25.76) + typescript: + specifier: ^5.9.3 + version: 5.9.3 + +packages: + + '@antfu/install-pkg@1.1.0': + resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} + + '@astro-community/astro-embed-baseline-status@0.2.1': + resolution: {integrity: sha512-IGEcAzjQ3OVVEbB0yB7GDlYz3TpY1X4ZBDz2+ejRP0yW3VZuPeWyoIffuKm9iGUomnqXs6hoVR6/vK0OmLXZRA==} + peerDependencies: + astro: ^4.0.0-beta || ^5.0.0-beta + + '@astro-community/astro-embed-bluesky@0.1.5': + resolution: {integrity: sha512-/0wruqqgcbB/z8KnUGETURvNwct5cKBcPit/gJus7oOQctT8+wUjWcIlCn3uyqaZUq6ghpbRsj2eSD75rJZzSQ==} + peerDependencies: + astro: ^4.0.0 || ^5.0.0-beta.0 + + '@astro-community/astro-embed-integration@0.8.3': + resolution: {integrity: sha512-lJfPOiol8lTay5kJHT3C4CmM6shF6mF2YZR2tSpM4F+D1tj26PZ937r0iHhUcOLPeQPmczZbs9Tx1WwDY4SjOQ==} + peerDependencies: + astro: ^2.0.0 || ^3.0.0-beta || ^4.0.0-beta || ^5.0.0-beta + + '@astro-community/astro-embed-link-preview@0.2.3': + resolution: {integrity: sha512-TLnZOihoQhXOCybvbzE/ImqFkGgG5zSJeWIj+PytM41Q/uhU6w19LD571qmWADf0Grv/u7LtorR1PB6ijQnazQ==} + + '@astro-community/astro-embed-twitter@0.5.9': + resolution: {integrity: sha512-bTIP/2LB3iEzlZ58L7dFyLJuWLeFDXgzZUQZKlWIfsXiKYqKIfLTQ01U10sh9UiHpm1M+4kOVPpue5LbUpJXHw==} + peerDependencies: + astro: ^2.0.0 || ^3.0.0-beta || ^4.0.0-beta || ^5.0.0-beta + + '@astro-community/astro-embed-utils@0.1.5': + resolution: {integrity: sha512-0RlP7J1YEWrguWDfEDsm4uDCXk4FKn0HHakmSOSwHLg6YR8WNEN/LGMGhhsxLc/mDqO2lRh1VqfJy+yPLLkzsQ==} + + '@astro-community/astro-embed-vimeo@0.3.11': + resolution: {integrity: sha512-uvTLmG5z9WGoyKac86Fxh6YnmBwlEQOalbi1/BatUy9zfQ/5x8rFs+U5xiM1nW38dGmDw/Hj7Nq3ljnZxy6PMA==} + peerDependencies: + astro: ^2.0.0 || ^3.0.0-beta || ^4.0.0-beta || ^5.0.0-beta + + '@astro-community/astro-embed-youtube@0.5.9': + resolution: {integrity: sha512-8Uk2SKbyZVb+jxwqSAMoEpQo+063XYwCI3yRy9cbkyHpu09mDabGZNTF5XrL8CKr3NtR5haBkeYK/kSuKUkJ/g==} + peerDependencies: + astro: ^2.0.0 || ^3.0.0-beta || ^4.0.0-beta || ^5.0.0-beta + + '@astrojs/compiler@2.13.0': + resolution: {integrity: sha512-mqVORhUJViA28fwHYaWmsXSzLO9osbdZ5ImUfxBarqsYdMlPbqAqGJCxsNzvppp1BEzc1mJNjOVvQqeDN8Vspw==} + + '@astrojs/internal-helpers@0.7.5': + resolution: {integrity: sha512-vreGnYSSKhAjFJCWAwe/CNhONvoc5lokxtRoZims+0wa3KbHBdPHSSthJsKxPd8d/aic6lWKpRTYGY/hsgK6EA==} + + '@astrojs/markdown-remark@6.3.10': + resolution: {integrity: sha512-kk4HeYR6AcnzC4QV8iSlOfh+N8TZ3MEStxPyenyCtemqn8IpEATBFMTJcfrNW32dgpt6MY3oCkMM/Tv3/I4G3A==} + + '@astrojs/mdx@4.3.13': + resolution: {integrity: sha512-IHDHVKz0JfKBy3//52JSiyWv089b7GVSChIXLrlUOoTLWowG3wr2/8hkaEgEyd/vysvNQvGk+QhysXpJW5ve6Q==} + engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0} + peerDependencies: + astro: ^5.0.0 + + '@astrojs/prism@3.3.0': + resolution: {integrity: sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ==} + engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0} + + '@astrojs/sitemap@3.6.0': + resolution: {integrity: sha512-4aHkvcOZBWJigRmMIAJwRQXBS+ayoP5z40OklTXYXhUDhwusz+DyDl+nSshY6y9DvkVEavwNcFO8FD81iGhXjg==} + + '@astrojs/starlight@0.36.3': + resolution: {integrity: sha512-5cm4QVQHUP6ZE52O43TtUpsTvLKdZa9XEs4l3suzuY7Ymsbz4ojtoL9NhistbMqM+/qk6fm6SmxbOL6hQ/LfNA==} + peerDependencies: + astro: ^5.5.0 + + '@astrojs/telemetry@3.3.0': + resolution: {integrity: sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ==} + engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0} + + '@atproto/api@0.13.35': + resolution: {integrity: sha512-vsEfBj0C333TLjDppvTdTE0IdKlXuljKSveAeI4PPx/l6eUKNnDTsYxvILtXUVzwUlTDmSRqy5O4Ryh78n1b7g==} + + '@atproto/common-web@0.4.7': + resolution: {integrity: sha512-vjw2+81KPo2/SAbbARGn64Ln+6JTI0FTI4xk8if0ebBfDxFRmHb2oSN1y77hzNq/ybGHqA2mecfhS03pxC5+lg==} + + '@atproto/lex-data@0.0.3': + resolution: {integrity: sha512-ivo1IpY/EX+RIpxPgCf4cPhQo5bfu4nrpa1vJCt8hCm9SfoonJkDFGa0n4SMw4JnXZoUcGcrJ46L+D8bH6GI2g==} + + '@atproto/lex-json@0.0.3': + resolution: {integrity: sha512-ZVcY7XlRfdPYvQQ2WroKUepee0+NCovrSXgXURM3Xv+n5jflJCoczguROeRr8sN0xvT0ZbzMrDNHCUYKNnxcjw==} + + '@atproto/lexicon@0.4.14': + resolution: {integrity: sha512-jiKpmH1QER3Gvc7JVY5brwrfo+etFoe57tKPQX/SmPwjvUsFnJAow5xLIryuBaJgFAhnTZViXKs41t//pahGHQ==} + + '@atproto/syntax@0.3.4': + resolution: {integrity: sha512-8CNmi5DipOLaVeSMPggMe7FCksVag0aO6XZy9WflbduTKM4dFZVCs4686UeMLfGRXX+X966XgwECHoLYrovMMg==} + + '@atproto/syntax@0.4.2': + resolution: {integrity: sha512-X9XSRPinBy/0VQ677j8VXlBsYSsUXaiqxWVpGGxJYsAhugdQRb0jqaVKJFtm6RskeNkV6y9xclSUi9UYG/COrA==} + + '@atproto/xrpc@0.6.12': + resolution: {integrity: sha512-Ut3iISNLujlmY9Gu8sNU+SPDJDvqlVzWddU8qUr0Yae5oD4SguaUFjjhireMGhQ3M5E0KljQgDbTmnBo1kIZ3w==} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.28.5': + resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/runtime@7.28.4': + resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.28.5': + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + engines: {node: '>=6.9.0'} + + '@braintree/sanitize-url@7.1.1': + resolution: {integrity: sha512-i1L7noDNxtFyL5DmZafWy1wRVhGehQmzZaz1HiN5e7iylJMSZR7ekOV7NsIqa5qBldlLrsKv4HbgFUVlQrz8Mw==} + + '@capsizecss/unpack@3.0.1': + resolution: {integrity: sha512-8XqW8xGn++Eqqbz3e9wKuK7mxryeRjs4LOHLxbh2lwKeSbuNR4NFifDZT4KzvjU6HMOPbiNTsWpniK5EJfTWkg==} + engines: {node: '>=18'} + + '@chevrotain/cst-dts-gen@11.0.3': + resolution: {integrity: sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==} + + '@chevrotain/gast@11.0.3': + resolution: {integrity: sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==} + + '@chevrotain/regexp-to-ast@11.0.3': + resolution: {integrity: sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==} + + '@chevrotain/types@11.0.3': + resolution: {integrity: sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==} + + '@chevrotain/utils@11.0.3': + resolution: {integrity: sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==} + + '@ctrl/tinycolor@4.2.0': + resolution: {integrity: sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==} + engines: {node: '>=14'} + + '@emnapi/runtime@1.7.1': + resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} + + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@expressive-code/core@0.41.5': + resolution: {integrity: sha512-II5TEy5eOoXiqPwqtpSqwamUd7lZS3YH3ofxR1ZyQMmygqORZn8/7SzgfF8G0kB7uKCBzFZT6RgKgCuHcJuPpA==} + + '@expressive-code/plugin-frames@0.41.5': + resolution: {integrity: sha512-qU0cvAQGfRLX7XwGf3/+hqIVmAc/mNNTlqVLR0iBfJF6EKvtP3R7/uAlPrAxnxQxn0meTazCz8D+PsPyOpHKrQ==} + + '@expressive-code/plugin-shiki@0.41.5': + resolution: {integrity: sha512-gw6OWvnmDmvcKJ5AZSzl2VkuixJMQ/zWSwPLFNzitqCa8aPfIFunb0K8IIOsE43LELgOWkie9lRFspOxwDVwrg==} + + '@expressive-code/plugin-text-markers@0.41.5': + resolution: {integrity: sha512-0DSiTsjWFEz6/iuLOGNNy2GaeCW41OwnVJMKx1tS+XKeQxAL89UkZP3egWNzxjWNHNMzEv3ZWWWYqbonEQlv/Q==} + + '@iconify/types@2.0.0': + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + + '@iconify/utils@3.1.0': + resolution: {integrity: sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw==} + + '@img/colour@1.0.0': + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@mdx-js/mdx@3.1.1': + resolution: {integrity: sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==} + + '@mermaid-js/parser@0.6.3': + resolution: {integrity: sha512-lnjOhe7zyHjc+If7yT4zoedx2vo4sHaTmtkl1+or8BRTnCtDmcTpAjpzDSfCZrshM5bCoz0GyidzadJAH1xobA==} + + '@oslojs/encoding@1.1.0': + resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==} + + '@pagefind/darwin-arm64@1.4.0': + resolution: {integrity: sha512-2vMqkbv3lbx1Awea90gTaBsvpzgRs7MuSgKDxW0m9oV1GPZCZbZBJg/qL83GIUEN2BFlY46dtUZi54pwH+/pTQ==} + cpu: [arm64] + os: [darwin] + + '@pagefind/darwin-x64@1.4.0': + resolution: {integrity: sha512-e7JPIS6L9/cJfow+/IAqknsGqEPjJnVXGjpGm25bnq+NPdoD3c/7fAwr1OXkG4Ocjx6ZGSCijXEV4ryMcH2E3A==} + cpu: [x64] + os: [darwin] + + '@pagefind/default-ui@1.4.0': + resolution: {integrity: sha512-wie82VWn3cnGEdIjh4YwNESyS1G6vRHwL6cNjy9CFgNnWW/PGRjsLq300xjVH5sfPFK3iK36UxvIBymtQIEiSQ==} + + '@pagefind/freebsd-x64@1.4.0': + resolution: {integrity: sha512-WcJVypXSZ+9HpiqZjFXMUobfFfZZ6NzIYtkhQ9eOhZrQpeY5uQFqNWLCk7w9RkMUwBv1HAMDW3YJQl/8OqsV0Q==} + cpu: [x64] + os: [freebsd] + + '@pagefind/linux-arm64@1.4.0': + resolution: {integrity: sha512-PIt8dkqt4W06KGmQjONw7EZbhDF+uXI7i0XtRLN1vjCUxM9vGPdtJc2mUyVPevjomrGz5M86M8bqTr6cgDp1Uw==} + cpu: [arm64] + os: [linux] + + '@pagefind/linux-x64@1.4.0': + resolution: {integrity: sha512-z4oddcWwQ0UHrTHR8psLnVlz6USGJ/eOlDPTDYZ4cI8TK8PgwRUPQZp9D2iJPNIPcS6Qx/E4TebjuGJOyK8Mmg==} + cpu: [x64] + os: [linux] + + '@pagefind/windows-x64@1.4.0': + resolution: {integrity: sha512-NkT+YAdgS2FPCn8mIA9bQhiBs+xmniMGq1LFPDhcFn0+2yIUEiIG06t7bsZlhdjknEQRTSdT7YitP6fC5qwP0g==} + cpu: [x64] + os: [win32] + + '@pasqal-io/starlight-client-mermaid@0.1.0': + resolution: {integrity: sha512-ocVamqp4wvR0yATyi0G0s+UVuIn/4AIubBlAcRPhQwICngTq2y1SaK38u99NS+7ZCFqetz5FeX3hKeCwkh4yHw==} + engines: {node: ^18.17.1 || ^20.3.0 || >=21.0.0} + peerDependencies: + '@astrojs/markdown-remark': ^6.0.2 + '@astrojs/starlight': '>=0.31' + + '@rollup/pluginutils@5.3.0': + resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/rollup-android-arm-eabi@4.54.0': + resolution: {integrity: sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.54.0': + resolution: {integrity: sha512-Skx39Uv+u7H224Af+bDgNinitlmHyQX1K/atIA32JP3JQw6hVODX5tkbi2zof/E69M1qH2UoN3Xdxgs90mmNYw==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.54.0': + resolution: {integrity: sha512-k43D4qta/+6Fq+nCDhhv9yP2HdeKeP56QrUUTW7E6PhZP1US6NDqpJj4MY0jBHlJivVJD5P8NxrjuobZBJTCRw==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.54.0': + resolution: {integrity: sha512-cOo7biqwkpawslEfox5Vs8/qj83M/aZCSSNIWpVzfU2CYHa2G3P1UN5WF01RdTHSgCkri7XOlTdtk17BezlV3A==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.54.0': + resolution: {integrity: sha512-miSvuFkmvFbgJ1BevMa4CPCFt5MPGw094knM64W9I0giUIMMmRYcGW/JWZDriaw/k1kOBtsWh1z6nIFV1vPNtA==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.54.0': + resolution: {integrity: sha512-KGXIs55+b/ZfZsq9aR026tmr/+7tq6VG6MsnrvF4H8VhwflTIuYh+LFUlIsRdQSgrgmtM3fVATzEAj4hBQlaqQ==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.54.0': + resolution: {integrity: sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.54.0': + resolution: {integrity: sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.54.0': + resolution: {integrity: sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.54.0': + resolution: {integrity: sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.54.0': + resolution: {integrity: sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.54.0': + resolution: {integrity: sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.54.0': + resolution: {integrity: sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.54.0': + resolution: {integrity: sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.54.0': + resolution: {integrity: sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.54.0': + resolution: {integrity: sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.54.0': + resolution: {integrity: sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openharmony-arm64@4.54.0': + resolution: {integrity: sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.54.0': + resolution: {integrity: sha512-c2V0W1bsKIKfbLMBu/WGBz6Yci8nJ/ZJdheE0EwB73N3MvHYKiKGs3mVilX4Gs70eGeDaMqEob25Tw2Gb9Nqyw==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.54.0': + resolution: {integrity: sha512-woEHgqQqDCkAzrDhvDipnSirm5vxUXtSKDYTVpZG3nUdW/VVB5VdCYA2iReSj/u3yCZzXID4kuKG7OynPnB3WQ==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.54.0': + resolution: {integrity: sha512-dzAc53LOuFvHwbCEOS0rPbXp6SIhAf2txMP5p6mGyOXXw5mWY8NGGbPMPrs4P1WItkfApDathBj/NzMLUZ9rtQ==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.54.0': + resolution: {integrity: sha512-hYT5d3YNdSh3mbCU1gwQyPgQd3T2ne0A3KG8KSBdav5TiBg6eInVmV+TeR5uHufiIgSFg0XsOWGW5/RhNcSvPg==} + cpu: [x64] + os: [win32] + + '@shikijs/core@3.20.0': + resolution: {integrity: sha512-f2ED7HYV4JEk827mtMDwe/yQ25pRiXZmtHjWF8uzZKuKiEsJR7Ce1nuQ+HhV9FzDcbIo4ObBCD9GPTzNuy9S1g==} + + '@shikijs/engine-javascript@3.20.0': + resolution: {integrity: sha512-OFx8fHAZuk7I42Z9YAdZ95To6jDePQ9Rnfbw9uSRTSbBhYBp1kEOKv/3jOimcj3VRUKusDYM6DswLauwfhboLg==} + + '@shikijs/engine-oniguruma@3.20.0': + resolution: {integrity: sha512-Yx3gy7xLzM0ZOjqoxciHjA7dAt5tyzJE3L4uQoM83agahy+PlW244XJSrmJRSBvGYELDhYXPacD4R/cauV5bzQ==} + + '@shikijs/langs@3.20.0': + resolution: {integrity: sha512-le+bssCxcSHrygCWuOrYJHvjus6zhQ2K7q/0mgjiffRbkhM4o1EWu2m+29l0yEsHDbWaWPNnDUTRVVBvBBeKaA==} + + '@shikijs/themes@3.20.0': + resolution: {integrity: sha512-U1NSU7Sl26Q7ErRvJUouArxfM2euWqq1xaSrbqMu2iqa+tSp0D1Yah8216sDYbdDHw4C8b75UpE65eWorm2erQ==} + + '@shikijs/types@3.20.0': + resolution: {integrity: sha512-lhYAATn10nkZcBQ0BlzSbJA3wcmL5MXUUF8d2Zzon6saZDlToKaiRX60n2+ZaHJCmXEcZRWNzn+k9vplr8Jhsw==} + + '@shikijs/vscode-textmate@10.0.2': + resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + + '@swc/helpers@0.5.18': + resolution: {integrity: sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ==} + + '@types/d3-array@3.2.2': + resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} + + '@types/d3-axis@3.0.6': + resolution: {integrity: sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==} + + '@types/d3-brush@3.0.6': + resolution: {integrity: sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==} + + '@types/d3-chord@3.0.6': + resolution: {integrity: sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==} + + '@types/d3-color@3.1.3': + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + + '@types/d3-contour@3.0.6': + resolution: {integrity: sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==} + + '@types/d3-delaunay@6.0.4': + resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==} + + '@types/d3-dispatch@3.0.7': + resolution: {integrity: sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==} + + '@types/d3-drag@3.0.7': + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + + '@types/d3-dsv@3.0.7': + resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==} + + '@types/d3-ease@3.0.2': + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + + '@types/d3-fetch@3.0.7': + resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==} + + '@types/d3-force@3.0.10': + resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==} + + '@types/d3-format@3.0.4': + resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==} + + '@types/d3-geo@3.1.0': + resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==} + + '@types/d3-hierarchy@3.1.7': + resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} + + '@types/d3-interpolate@3.0.4': + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + + '@types/d3-path@3.1.1': + resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} + + '@types/d3-polygon@3.0.2': + resolution: {integrity: sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==} + + '@types/d3-quadtree@3.0.6': + resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} + + '@types/d3-random@3.0.3': + resolution: {integrity: sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==} + + '@types/d3-scale-chromatic@3.1.0': + resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==} + + '@types/d3-scale@4.0.9': + resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} + + '@types/d3-selection@3.0.11': + resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + + '@types/d3-shape@3.1.7': + resolution: {integrity: sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==} + + '@types/d3-time-format@4.0.3': + resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} + + '@types/d3-time@3.0.4': + resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} + + '@types/d3-timer@3.0.2': + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + + '@types/d3-transition@3.0.9': + resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} + + '@types/d3-zoom@3.0.8': + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + + '@types/d3@7.4.3': + resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} + + '@types/debug@4.1.12': + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + + '@types/estree-jsx@1.0.5': + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/fontkit@2.0.8': + resolution: {integrity: sha512-wN+8bYxIpJf+5oZdrdtaX04qUuWHcKxcDEgRS9Qm9ZClSHjzEn13SxUC+5eRM+4yXIeTYk8mTzLAWGF64847ew==} + + '@types/geojson@7946.0.16': + resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} + + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + + '@types/js-yaml@4.0.9': + resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/mdx@2.0.13': + resolution: {integrity: sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/nlcst@2.0.3': + resolution: {integrity: sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==} + + '@types/node-fetch@2.6.13': + resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==} + + '@types/node@17.0.45': + resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==} + + '@types/node@18.19.130': + resolution: {integrity: sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==} + + '@types/node@25.0.3': + resolution: {integrity: sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==} + + '@types/sax@1.2.7': + resolution: {integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==} + + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + agentkeepalive@4.6.0: + resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} + engines: {node: '>= 8.0.0'} + + ansi-align@3.0.1: + resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + array-iterate@2.0.1: + resolution: {integrity: sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==} + + astring@1.9.0: + resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} + hasBin: true + + astro-auto-import@0.4.5: + resolution: {integrity: sha512-KU1qFJ97Qks2aT+qSxjrOY6tcwzzLVhY/8w1eM8vwqpP+MDpHKAlbr8Otg9T8g/Mfl/FOdG3nO9lydv1zbtyQA==} + engines: {node: '>=16.0.0'} + peerDependencies: + astro: ^2.0.0 || ^3.0.0-beta || ^4.0.0-beta || ^5.0.0-beta + + astro-embed@0.9.2: + resolution: {integrity: sha512-MUeNrfnNgcrV9E8WqEW9IYK8+Y3etDLyyi8Uf35rM5WJ53wkh511ye9oi15taJuqOaYRk2hQ9P5G2+/JS1Mjxg==} + peerDependencies: + astro: ^2.0.0 || ^3.0.0-beta || ^4.0.0-beta || ^5.0.0-beta + + astro-expressive-code@0.41.5: + resolution: {integrity: sha512-6jfABbPO0fkRD1ROAPBQtJR2p7gjbmk/GjfblOpo5Z7F+gwhL7+s8bEhLz9GdW10yfbn+gJvwEf7f9Lu2clh2A==} + peerDependencies: + astro: ^4.0.0-beta || ^5.0.0-beta || ^3.3.0 + + astro@5.16.6: + resolution: {integrity: sha512-6mF/YrvwwRxLTu+aMEa5pwzKUNl5ZetWbTyZCs9Um0F12HUmxUiF5UHiZPy4rifzU3gtpM3xP2DfdmkNX9eZRg==} + engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0'} + hasBin: true + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + await-lock@2.2.2: + resolution: {integrity: sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw==} + + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + + bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + + base-64@1.0.0: + resolution: {integrity: sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + bcp-47-match@2.0.3: + resolution: {integrity: sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==} + + bcp-47@2.1.0: + resolution: {integrity: sha512-9IIS3UPrvIa1Ej+lVDdDwO7zLehjqsaByECw0bu2RRGP73jALm6FYbzI5gWbgHLvNdkvfXB5YrSbocZdOS0c0w==} + + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + + boxen@8.0.1: + resolution: {integrity: sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==} + engines: {node: '>=18'} + + brotli@1.3.3: + resolution: {integrity: sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + camelcase@8.0.0: + resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==} + engines: {node: '>=16'} + + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + + chevrotain-allstar@0.3.1: + resolution: {integrity: sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==} + peerDependencies: + chevrotain: ^11.0.0 + + chevrotain@11.0.3: + resolution: {integrity: sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + ci-info@4.3.1: + resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==} + engines: {node: '>=8'} + + cli-boxes@3.0.0: + resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} + engines: {node: '>=10'} + + clone@2.1.2: + resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==} + engines: {node: '>=0.8'} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + collapse-white-space@2.1.0: + resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + + commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} + + commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + + commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + + common-ancestor-path@1.0.1: + resolution: {integrity: sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==} + + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + cookie-es@1.2.2: + resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==} + + cookie@1.1.1: + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} + engines: {node: '>=18'} + + cose-base@1.0.3: + resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==} + + cose-base@2.2.0: + resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==} + + crossws@0.3.5: + resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==} + + css-select@5.2.2: + resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} + + css-selector-parser@1.4.1: + resolution: {integrity: sha512-HYPSb7y/Z7BNDCOrakL4raGO2zltZkbeXyAd6Tg9obzix6QhzxCotdBl6VT0Dv4vZfJGVz3WL/xaEI9Ly3ul0g==} + + css-selector-parser@3.3.0: + resolution: {integrity: sha512-Y2asgMGFqJKF4fq4xHDSlFYIkeVfRsm69lQC1q9kbEsH5XtnINTMrweLkjYMeaUgiXBy/uvKeO/a1JHTNnmB2g==} + + css-tree@2.2.1: + resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + + css-tree@3.1.0: + resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + + css-what@6.2.2: + resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} + engines: {node: '>= 6'} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + csso@5.0.5: + resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + + cssom@0.5.0: + resolution: {integrity: sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==} + + cytoscape-cose-bilkent@4.1.0: + resolution: {integrity: sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape-fcose@2.2.0: + resolution: {integrity: sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape@3.33.1: + resolution: {integrity: sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==} + engines: {node: '>=0.10'} + + d3-array@2.12.1: + resolution: {integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==} + + d3-array@3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + + d3-axis@3.0.0: + resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} + engines: {node: '>=12'} + + d3-brush@3.0.0: + resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} + engines: {node: '>=12'} + + d3-chord@3.0.1: + resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} + engines: {node: '>=12'} + + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-contour@4.0.2: + resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} + engines: {node: '>=12'} + + d3-delaunay@6.0.4: + resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} + engines: {node: '>=12'} + + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + + d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + + d3-dsv@3.0.1: + resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} + engines: {node: '>=12'} + hasBin: true + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-fetch@3.0.1: + resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} + engines: {node: '>=12'} + + d3-force@3.0.0: + resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} + engines: {node: '>=12'} + + d3-format@3.1.0: + resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==} + engines: {node: '>=12'} + + d3-geo@3.1.1: + resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} + engines: {node: '>=12'} + + d3-hierarchy@3.1.2: + resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} + engines: {node: '>=12'} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-path@1.0.9: + resolution: {integrity: sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==} + + d3-path@3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + + d3-polygon@3.0.1: + resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} + engines: {node: '>=12'} + + d3-quadtree@3.0.1: + resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} + engines: {node: '>=12'} + + d3-random@3.0.1: + resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} + engines: {node: '>=12'} + + d3-sankey@0.12.3: + resolution: {integrity: sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==} + + d3-scale-chromatic@3.1.0: + resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} + engines: {node: '>=12'} + + d3-scale@4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + + d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + + d3-shape@1.3.7: + resolution: {integrity: sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==} + + d3-shape@3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + + d3-time-format@4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + + d3-time@3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + + d3-transition@3.0.1: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + + d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + + d3@7.9.0: + resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} + engines: {node: '>=12'} + + dagre-d3-es@7.0.13: + resolution: {integrity: sha512-efEhnxpSuwpYOKRm/L5KbqoZmNNukHa/Flty4Wp62JRvgH2ojwVgPgdYyr4twpieZnyRDdIH7PY2mopX26+j2Q==} + + dayjs@1.11.19: + resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decode-named-character-reference@1.2.0: + resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==} + + defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + + delaunator@5.0.1: + resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + destr@2.0.5: + resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + deterministic-object-hash@2.0.2: + resolution: {integrity: sha512-KxektNH63SrbfUyDiwXqRb1rLwKt33AmMv+5Nhsw1kqZ13SJBRTgZHtGbE+hH3a1mVW1cz+4pqSWVPAtLVXTzQ==} + engines: {node: '>=18'} + + devalue@5.6.1: + resolution: {integrity: sha512-jDwizj+IlEZBunHcOuuFVBnIMPAEHvTsJj0BcIp94xYguLRVBcXO853px/MyIJvbVzWdsGvrRweIUWJw8hBP7A==} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + dfa@1.2.0: + resolution: {integrity: sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==} + + diff@5.2.0: + resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} + engines: {node: '>=0.3.1'} + + direction@2.0.1: + resolution: {integrity: sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA==} + hasBin: true + + dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + + dompurify@3.3.1: + resolution: {integrity: sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==} + + domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + + dset@3.1.4: + resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==} + engines: {node: '>=4'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + emoji-regex@10.6.0: + resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + esast-util-from-estree@2.0.0: + resolution: {integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==} + + esast-util-from-js@2.0.1: + resolution: {integrity: sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==} + + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + engines: {node: '>=18'} + hasBin: true + + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + + estree-util-attach-comments@3.0.0: + resolution: {integrity: sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==} + + estree-util-build-jsx@3.0.1: + resolution: {integrity: sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==} + + estree-util-is-identifier-name@3.0.0: + resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} + + estree-util-scope@1.0.0: + resolution: {integrity: sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==} + + estree-util-to-js@2.0.0: + resolution: {integrity: sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==} + + estree-util-visit@2.0.0: + resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==} + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + + eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + + expressive-code@0.41.5: + resolution: {integrity: sha512-iXl9BgDogQgzgE/WRSrcyU8upOcRZrXPMiu6tegEHML57YLQ65S0E3/sjAXmMZy0GXoPs60s9jbwoMo/mdEQOg==} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + flattie@1.1.1: + resolution: {integrity: sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==} + engines: {node: '>=8'} + + fontace@0.3.1: + resolution: {integrity: sha512-9f5g4feWT1jWT8+SbL85aLIRLIXUaDygaM2xPXRmzPYxrOMNok79Lr3FGJoKVNKibE0WCunNiEVG2mwuE+2qEg==} + + fontkit@2.0.4: + resolution: {integrity: sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g==} + + form-data-encoder@1.7.2: + resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==} + + form-data@4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + engines: {node: '>= 6'} + + formdata-node@4.4.1: + resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==} + engines: {node: '>= 12.20'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + get-east-asian-width@1.4.0: + resolution: {integrity: sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==} + engines: {node: '>=18'} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + github-slugger@2.0.0: + resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + h3@1.15.4: + resolution: {integrity: sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ==} + + hachure-fill@0.5.2: + resolution: {integrity: sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + hast-util-embedded@3.0.0: + resolution: {integrity: sha512-naH8sld4Pe2ep03qqULEtvYr7EjrLK2QHY8KJR6RJkTUjPGObe1vnx585uzem2hGra+s1q08DZZpfgDVYRbaXA==} + + hast-util-format@1.1.0: + resolution: {integrity: sha512-yY1UDz6bC9rDvCWHpx12aIBGRG7krurX0p0Fm6pT547LwDIZZiNr8a+IHDogorAdreULSEzP82Nlv5SZkHZcjA==} + + hast-util-from-html@2.0.3: + resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==} + + hast-util-from-parse5@8.0.3: + resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==} + + hast-util-has-property@3.0.0: + resolution: {integrity: sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==} + + hast-util-is-body-ok-link@3.0.1: + resolution: {integrity: sha512-0qpnzOBLztXHbHQenVB8uNuxTnm/QBFUOmdOSsEn7GnBtyY07+ENTWVFBAnXd/zEgd9/SUG3lRY7hSIBWRgGpQ==} + + hast-util-is-element@3.0.0: + resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} + + hast-util-minify-whitespace@1.0.1: + resolution: {integrity: sha512-L96fPOVpnclQE0xzdWb/D12VT5FabA7SnZOUMtL1DbXmYiHJMXZvFkIZfiMmTCNJHUeO2K9UYNXoVyfz+QHuOw==} + + hast-util-parse-selector@4.0.0: + resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} + + hast-util-phrasing@3.0.1: + resolution: {integrity: sha512-6h60VfI3uBQUxHqTyMymMZnEbNl1XmEGtOxxKYL7stY2o601COo62AWAYBQR9lZbYXYSBoxag8UpPRXK+9fqSQ==} + + hast-util-raw@9.1.0: + resolution: {integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==} + + hast-util-select@6.0.4: + resolution: {integrity: sha512-RqGS1ZgI0MwxLaKLDxjprynNzINEkRHY2i8ln4DDjgv9ZhcYVIHN9rlpiYsqtFwrgpYU361SyWDQcGNIBVu3lw==} + + hast-util-to-estree@3.1.3: + resolution: {integrity: sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==} + + hast-util-to-html@9.0.5: + resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} + + hast-util-to-jsx-runtime@2.3.6: + resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==} + + hast-util-to-parse5@8.0.1: + resolution: {integrity: sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==} + + hast-util-to-string@3.0.1: + resolution: {integrity: sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==} + + hast-util-to-text@4.0.2: + resolution: {integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==} + + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + + hastscript@9.0.1: + resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==} + + html-escaper@3.0.3: + resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==} + + html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + + html-whitespace-sensitive-tag-names@3.0.1: + resolution: {integrity: sha512-q+310vW8zmymYHALr1da4HyXUQ0zgiIwIicEfotYPWGN0OJVEN/58IJ3A4GBYcEq3LGAZqKb+ugvP0GNB9CEAA==} + + htmlparser2@10.0.0: + resolution: {integrity: sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==} + + http-cache-semantics@4.2.0: + resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} + + humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + + i18next@23.16.8: + resolution: {integrity: sha512-06r/TitrM88Mg5FdUXAKL96dJMzgqLE5dv3ryBAra4KCwD9mJ4ndOTS95ZuymIGoE+2hzfdaMak2X11/es7ZWg==} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + import-meta-resolve@4.2.0: + resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==} + + inline-style-parser@0.2.7: + resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} + + internmap@1.0.1: + resolution: {integrity: sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==} + + internmap@2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + + iron-webcrypto@1.2.1: + resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} + + is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + + is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + + is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + + is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + + is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + + is-wsl@3.1.0: + resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} + engines: {node: '>=16'} + + iso-datestring-validator@2.2.2: + resolution: {integrity: sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA==} + + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + + katex@0.16.27: + resolution: {integrity: sha512-aeQoDkuRWSqQN6nSvVCEFvfXdqo1OQiCmmW1kc9xSdjutPv7BGO7pqY9sQRJpMOGrEdfDgF2TfRXe5eUAD2Waw==} + hasBin: true + + khroma@2.1.0: + resolution: {integrity: sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==} + + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + + klona@2.0.6: + resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} + engines: {node: '>= 8'} + + langium@3.3.1: + resolution: {integrity: sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w==} + engines: {node: '>=16.0.0'} + + layout-base@1.0.2: + resolution: {integrity: sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==} + + layout-base@2.0.1: + resolution: {integrity: sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==} + + linkedom@0.18.12: + resolution: {integrity: sha512-jalJsOwIKuQJSeTvsgzPe9iJzyfVaEJiEXl+25EkKevsULHvMJzpNqwvj1jOESWdmgKDiXObyjOYwlUqG7wo1Q==} + engines: {node: '>=16'} + peerDependencies: + canvas: '>= 2' + peerDependenciesMeta: + canvas: + optional: true + + lite-youtube-embed@0.3.4: + resolution: {integrity: sha512-aXgxpwK7AIW58GEbRzA8EYaY4LWvF3FKak6B9OtSJmuNyLhX2ouD4cMTxz/yR5HFInhknaYd2jLWOTRTvT8oAw==} + + lodash-es@4.17.21: + resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + + lodash-es@4.17.22: + resolution: {integrity: sha512-XEawp1t0gxSi9x01glktRZ5HDy0HXqrM0x5pXQM98EaI0NxO6jVM7omDOxsuEo5UIASAnm2bRp1Jt/e0a2XU8Q==} + + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + magicast@0.5.1: + resolution: {integrity: sha512-xrHS24IxaLrvuo613F719wvOIv9xPHFWQHuvGUBmPnCA/3MQxKI3b+r7n1jAoDHmsbC5bRhTZYR77invLAxVnw==} + + markdown-extensions@2.0.0: + resolution: {integrity: sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==} + engines: {node: '>=16'} + + markdown-table@3.0.4: + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + + marked@16.4.2: + resolution: {integrity: sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==} + engines: {node: '>= 20'} + hasBin: true + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mdast-util-definitions@6.0.0: + resolution: {integrity: sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==} + + mdast-util-directive@3.1.0: + resolution: {integrity: sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q==} + + mdast-util-find-and-replace@3.0.2: + resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} + + mdast-util-from-markdown@2.0.2: + resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} + + mdast-util-gfm-autolink-literal@2.0.1: + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} + + mdast-util-gfm-footnote@2.1.0: + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} + + mdast-util-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} + + mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + + mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + + mdast-util-gfm@3.1.0: + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + + mdast-util-mdx-expression@2.0.1: + resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} + + mdast-util-mdx-jsx@3.2.0: + resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==} + + mdast-util-mdx@3.0.0: + resolution: {integrity: sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==} + + mdast-util-mdxjs-esm@2.0.1: + resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-hast@13.2.1: + resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + + mdn-data@2.0.28: + resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} + + mdn-data@2.12.2: + resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} + + mermaid@11.12.2: + resolution: {integrity: sha512-n34QPDPEKmaeCG4WDMGy0OT6PSyxKCfy2pJgShP+Qow2KLrvWjclwbc3yXfSIf4BanqWEhQEpngWwNp/XhZt6w==} + + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-extension-directive@3.0.2: + resolution: {integrity: sha512-wjcXHgk+PPdmvR58Le9d7zQYWy+vKEU9Se44p2CrCDPiLr2FMyiT4Fyb5UFKFC66wGB3kPlgD7q3TnoqPS7SZA==} + + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-strikethrough@2.1.0: + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} + + micromark-extension-gfm-table@2.1.1: + resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} + + micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + + micromark-extension-gfm-task-list-item@2.1.0: + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} + + micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + + micromark-extension-mdx-expression@3.0.1: + resolution: {integrity: sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==} + + micromark-extension-mdx-jsx@3.0.2: + resolution: {integrity: sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==} + + micromark-extension-mdx-md@2.0.0: + resolution: {integrity: sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==} + + micromark-extension-mdxjs-esm@3.0.0: + resolution: {integrity: sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==} + + micromark-extension-mdxjs@3.0.0: + resolution: {integrity: sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-mdx-expression@2.0.3: + resolution: {integrity: sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-events-to-acorn@2.0.3: + resolution: {integrity: sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mlly@1.8.0: + resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} + + mrmime@2.0.1: + resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} + engines: {node: '>=10'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + multiformats@9.9.0: + resolution: {integrity: sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + neotraverse@0.6.18: + resolution: {integrity: sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==} + engines: {node: '>= 10'} + + nlcst-to-string@4.0.0: + resolution: {integrity: sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==} + + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + deprecated: Use your platform's native DOMException instead + + node-fetch-native@1.6.7: + resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} + + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + node-mock-http@1.0.4: + resolution: {integrity: sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + + ofetch@1.5.1: + resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==} + + ohash@2.0.11: + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + + oniguruma-parser@0.12.1: + resolution: {integrity: sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==} + + oniguruma-to-es@4.3.4: + resolution: {integrity: sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA==} + + openai@4.104.0: + resolution: {integrity: sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA==} + hasBin: true + peerDependencies: + ws: ^8.18.0 + zod: ^3.23.8 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true + + p-limit@6.2.0: + resolution: {integrity: sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==} + engines: {node: '>=18'} + + p-queue@8.1.1: + resolution: {integrity: sha512-aNZ+VfjobsWryoiPnEApGGmf5WmNsCo9xu8dfaYamG5qaLP7ClhLN6NgsFe6SwJ2UbLEBK5dv9x8Mn5+RVhMWQ==} + engines: {node: '>=18'} + + p-timeout@6.1.4: + resolution: {integrity: sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==} + engines: {node: '>=14.16'} + + package-manager-detector@1.6.0: + resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==} + + pagefind@1.4.0: + resolution: {integrity: sha512-z2kY1mQlL4J8q5EIsQkLzQjilovKzfNVhX8De6oyE6uHpfFtyBaqUpcl/XzJC/4fjD8vBDyh1zolimIcVrCn9g==} + hasBin: true + + pako@0.2.9: + resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} + + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + + parse-latin@7.0.0: + resolution: {integrity: sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==} + + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + + path-data-parser@0.1.0: + resolution: {integrity: sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + piccolore@0.1.3: + resolution: {integrity: sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + points-on-curve@0.2.0: + resolution: {integrity: sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==} + + points-on-path@0.2.1: + resolution: {integrity: sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==} + + postcss-nested@6.2.0: + resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + + postcss-selector-parser@6.1.2: + resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} + engines: {node: '>=4'} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + + prismjs@1.30.0: + resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} + engines: {node: '>=6'} + + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + + property-information@7.1.0: + resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} + + radix3@1.1.2: + resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} + + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + + recma-build-jsx@1.0.0: + resolution: {integrity: sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==} + + recma-jsx@1.0.1: + resolution: {integrity: sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + recma-parse@1.0.0: + resolution: {integrity: sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==} + + recma-stringify@1.0.0: + resolution: {integrity: sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==} + + regex-recursion@6.0.2: + resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} + + regex-utilities@2.3.0: + resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} + + regex@6.1.0: + resolution: {integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==} + + rehype-expressive-code@0.41.5: + resolution: {integrity: sha512-SzKJyu7heDpkt+XE/AqeWsYMSMocE/5mpJXD6CMgstqJHSE9bxGNcLp3zL9Wne3M5iBsS4GJyOD2syV77kRveA==} + + rehype-format@5.0.1: + resolution: {integrity: sha512-zvmVru9uB0josBVpr946OR8ui7nJEdzZobwLOOqHb/OOD88W0Vk2SqLwoVOj0fM6IPCCO6TaV9CvQvJMWwukFQ==} + + rehype-parse@9.0.1: + resolution: {integrity: sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==} + + rehype-raw@7.0.0: + resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==} + + rehype-recma@1.0.0: + resolution: {integrity: sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==} + + rehype-stringify@10.0.1: + resolution: {integrity: sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==} + + rehype@13.0.2: + resolution: {integrity: sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==} + + remark-directive@3.0.1: + resolution: {integrity: sha512-gwglrEQEZcZYgVyG1tQuA+h58EZfq5CSULw7J90AFuCTyib1thgHPoqQ+h9iFvU6R+vnZ5oNFQR5QKgGpk741A==} + + remark-gfm@4.0.1: + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + + remark-mdx@3.1.1: + resolution: {integrity: sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==} + + remark-parse@11.0.0: + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + + remark-rehype@11.1.2: + resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + + remark-smartypants@3.0.2: + resolution: {integrity: sha512-ILTWeOriIluwEvPjv67v7Blgrcx+LZOkAUVtKI3putuhlZm84FnqDORNXPPm+HY3NdZOMhyDwZ1E+eZB/Df5dA==} + engines: {node: '>=16.0.0'} + + remark-stringify@11.0.0: + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + + restructure@3.0.2: + resolution: {integrity: sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==} + + retext-latin@4.0.0: + resolution: {integrity: sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==} + + retext-smartypants@6.2.0: + resolution: {integrity: sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==} + + retext-stringify@4.0.0: + resolution: {integrity: sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==} + + retext@9.0.0: + resolution: {integrity: sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==} + + robust-predicates@3.0.2: + resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} + + rollup@4.54.0: + resolution: {integrity: sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + roughjs@4.6.6: + resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==} + + rw@1.3.3: + resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + sax@1.4.3: + resolution: {integrity: sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==} + + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + shiki@3.20.0: + resolution: {integrity: sha512-kgCOlsnyWb+p0WU+01RjkCH+eBVsjL1jOwUYWv0YDWkM2/A46+LDKVs5yZCUXjJG6bj4ndFoAg5iLIIue6dulg==} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + sitemap@8.0.2: + resolution: {integrity: sha512-LwktpJcyZDoa0IL6KT++lQ53pbSrx2c9ge41/SeLTyqy2XUNA6uR4+P9u5IVo5lPeL2arAcOKn1aZAxoYbCKlQ==} + engines: {node: '>=14.0.0', npm: '>=6.0.0'} + hasBin: true + + smol-toml@1.6.0: + resolution: {integrity: sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw==} + engines: {node: '>= 18'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + + stream-replace-string@2.0.0: + resolution: {integrity: sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w==} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.1.2: + resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} + engines: {node: '>=12'} + + style-to-js@1.1.21: + resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} + + style-to-object@1.0.14: + resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} + + stylis@4.3.6: + resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==} + + svgo@4.0.0: + resolution: {integrity: sha512-VvrHQ+9uniE+Mvx3+C9IEe/lWasXCU0nXMY2kZeLrHNICuRiC8uMPyM14UEaMOFA5mhyQqEkB02VoQ16n3DLaw==} + engines: {node: '>=16'} + hasBin: true + + tiny-inflate@1.0.3: + resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==} + + tinyexec@1.0.2: + resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + engines: {node: '>=18'} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + tlds@1.261.0: + resolution: {integrity: sha512-QXqwfEl9ddlGBaRFXIvNKK6OhipSiLXuRuLJX5DErz0o0Q0rYxulWLdFryTkV5PkdZct5iMInwYEGe/eR++1AA==} + hasBin: true + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + + trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + + ts-dedent@2.2.0: + resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} + engines: {node: '>=6.10'} + + ts-pattern@5.9.0: + resolution: {integrity: sha512-6s5V71mX8qBUmlgbrfL33xDUwO0fq48rxAu2LBE11WBeGdpCPOsXksQbZJHvHwhrd3QjUusd3mAOM5Gg0mFBLg==} + + tsconfck@3.1.6: + resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==} + engines: {node: ^18 || >=20} + hasBin: true + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + ufo@1.6.1: + resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} + + uhyphen@0.2.0: + resolution: {integrity: sha512-qz3o9CHXmJJPGBdqzab7qAYuW8kQGKNEuoHFYrBwV6hWIMcpAmxDLXojcHfFr9US1Pe6zUswEIJIbLI610fuqA==} + + uint8arrays@3.0.0: + resolution: {integrity: sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA==} + + ultrahtml@1.6.0: + resolution: {integrity: sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==} + + uncrypto@0.1.3: + resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} + + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + + undici-types@7.16.0: + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + + unicode-properties@1.4.1: + resolution: {integrity: sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==} + + unicode-segmenter@0.14.4: + resolution: {integrity: sha512-pR5VCiCrLrKOL6FRW61jnk9+wyMtKKowq+jyFY9oc6uHbWKhDL4yVRiI4YZPksGMK72Pahh8m0cn/0JvbDDyJg==} + + unicode-trie@2.0.0: + resolution: {integrity: sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==} + + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + unifont@0.6.0: + resolution: {integrity: sha512-5Fx50fFQMQL5aeHyWnZX9122sSLckcDvcfFiBf3QYeHa7a1MKJooUy52b67moi2MJYkrfo/TWY+CoLdr/w0tTA==} + + unist-util-find-after@5.0.0: + resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-modify-children@4.0.0: + resolution: {integrity: sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw==} + + unist-util-position-from-estree@2.0.0: + resolution: {integrity: sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==} + + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + + unist-util-remove-position@5.0.0: + resolution: {integrity: sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==} + + unist-util-select@4.0.3: + resolution: {integrity: sha512-1074+K9VyR3NyUz3lgNtHKm7ln+jSZXtLJM4E22uVuoFn88a/Go2pX8dusrt/W+KWH1ncn8jcd8uCQuvXb/fXA==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-children@3.0.0: + resolution: {integrity: sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.0.0: + resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + + unstorage@1.17.3: + resolution: {integrity: sha512-i+JYyy0DoKmQ3FximTHbGadmIYb8JEpq7lxUjnjeB702bCPum0vzo6oy5Mfu0lpqISw7hCyMW2yj4nWC8bqJ3Q==} + peerDependencies: + '@azure/app-configuration': ^1.8.0 + '@azure/cosmos': ^4.2.0 + '@azure/data-tables': ^13.3.0 + '@azure/identity': ^4.6.0 + '@azure/keyvault-secrets': ^4.9.0 + '@azure/storage-blob': ^12.26.0 + '@capacitor/preferences': ^6.0.3 || ^7.0.0 + '@deno/kv': '>=0.9.0' + '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0 + '@planetscale/database': ^1.19.0 + '@upstash/redis': ^1.34.3 + '@vercel/blob': '>=0.27.1' + '@vercel/functions': ^2.2.12 || ^3.0.0 + '@vercel/kv': ^1.0.1 + aws4fetch: ^1.0.20 + db0: '>=0.2.1' + idb-keyval: ^6.2.1 + ioredis: ^5.4.2 + uploadthing: ^7.4.4 + peerDependenciesMeta: + '@azure/app-configuration': + optional: true + '@azure/cosmos': + optional: true + '@azure/data-tables': + optional: true + '@azure/identity': + optional: true + '@azure/keyvault-secrets': + optional: true + '@azure/storage-blob': + optional: true + '@capacitor/preferences': + optional: true + '@deno/kv': + optional: true + '@netlify/blobs': + optional: true + '@planetscale/database': + optional: true + '@upstash/redis': + optional: true + '@vercel/blob': + optional: true + '@vercel/functions': + optional: true + '@vercel/kv': + optional: true + aws4fetch: + optional: true + db0: + optional: true + idb-keyval: + optional: true + ioredis: + optional: true + uploadthing: + optional: true + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + uuid@11.1.0: + resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} + hasBin: true + + vfile-location@5.0.3: + resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + + vite@6.4.1: + resolution: {integrity: sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: '>=1.21.0' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitefu@1.1.1: + resolution: {integrity: sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==} + peerDependencies: + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0 + peerDependenciesMeta: + vite: + optional: true + + vscode-jsonrpc@8.2.0: + resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} + engines: {node: '>=14.0.0'} + + vscode-languageserver-protocol@3.17.5: + resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} + + vscode-languageserver-textdocument@1.0.12: + resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==} + + vscode-languageserver-types@3.17.5: + resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} + + vscode-languageserver@9.0.1: + resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} + hasBin: true + + vscode-uri@3.0.8: + resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} + + web-namespaces@2.0.1: + resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + + web-streams-polyfill@4.0.0-beta.3: + resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==} + engines: {node: '>= 14'} + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + which-pm-runs@1.1.0: + resolution: {integrity: sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==} + engines: {node: '>=4'} + + widest-line@5.0.0: + resolution: {integrity: sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==} + engines: {node: '>=18'} + + wrap-ansi@9.0.2: + resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} + engines: {node: '>=18'} + + xxhash-wasm@1.1.0: + resolution: {integrity: sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yocto-queue@1.2.2: + resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} + engines: {node: '>=12.20'} + + yocto-spinner@0.2.3: + resolution: {integrity: sha512-sqBChb33loEnkoXte1bLg45bEBsOP9N1kzQh5JZNKj/0rik4zAPTNSAVPj3uQAdc6slYJ0Ksc403G2XgxsJQFQ==} + engines: {node: '>=18.19'} + + yoctocolors@2.1.2: + resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==} + engines: {node: '>=18'} + + zod-to-json-schema@3.25.0: + resolution: {integrity: sha512-HvWtU2UG41LALjajJrML6uQejQhNJx+JBO9IflpSja4R03iNWfKXrj6W2h7ljuLyc1nKS+9yDyL/9tD1U/yBnQ==} + peerDependencies: + zod: ^3.25 || ^4 + + zod-to-ts@1.2.0: + resolution: {integrity: sha512-x30XE43V+InwGpvTySRNz9kB7qFU8DlyEy7BsSTCHPH1R0QasMmHWZDCzYm6bVXtj/9NNJAZF3jW8rzFvH5OFA==} + peerDependencies: + typescript: ^4.9.4 || ^5.0.2 + zod: ^3 + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + +snapshots: + + '@antfu/install-pkg@1.1.0': + dependencies: + package-manager-detector: 1.6.0 + tinyexec: 1.0.2 + + '@astro-community/astro-embed-baseline-status@0.2.1(astro@5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3))': + dependencies: + '@astro-community/astro-embed-utils': 0.1.5 + astro: 5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3) + transitivePeerDependencies: + - canvas + + '@astro-community/astro-embed-bluesky@0.1.5(astro@5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3))': + dependencies: + '@atproto/api': 0.13.35 + astro: 5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3) + ts-pattern: 5.9.0 + + '@astro-community/astro-embed-integration@0.8.3(astro@5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3))': + dependencies: + '@astro-community/astro-embed-bluesky': 0.1.5(astro@5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3)) + '@astro-community/astro-embed-link-preview': 0.2.3 + '@astro-community/astro-embed-twitter': 0.5.9(astro@5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3)) + '@astro-community/astro-embed-vimeo': 0.3.11(astro@5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3)) + '@astro-community/astro-embed-youtube': 0.5.9(astro@5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3)) + '@types/unist': 2.0.11 + astro: 5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3) + astro-auto-import: 0.4.5(astro@5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3)) + unist-util-select: 4.0.3 + transitivePeerDependencies: + - canvas + + '@astro-community/astro-embed-link-preview@0.2.3': + dependencies: + '@astro-community/astro-embed-utils': 0.1.5 + transitivePeerDependencies: + - canvas + + '@astro-community/astro-embed-twitter@0.5.9(astro@5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3))': + dependencies: + '@astro-community/astro-embed-utils': 0.1.5 + astro: 5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3) + transitivePeerDependencies: + - canvas + + '@astro-community/astro-embed-utils@0.1.5': + dependencies: + linkedom: 0.18.12 + transitivePeerDependencies: + - canvas + + '@astro-community/astro-embed-vimeo@0.3.11(astro@5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3))': + dependencies: + '@astro-community/astro-embed-utils': 0.1.5 + astro: 5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3) + transitivePeerDependencies: + - canvas + + '@astro-community/astro-embed-youtube@0.5.9(astro@5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3))': + dependencies: + astro: 5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3) + lite-youtube-embed: 0.3.4 + + '@astrojs/compiler@2.13.0': {} + + '@astrojs/internal-helpers@0.7.5': {} + + '@astrojs/markdown-remark@6.3.10': + dependencies: + '@astrojs/internal-helpers': 0.7.5 + '@astrojs/prism': 3.3.0 + github-slugger: 2.0.0 + hast-util-from-html: 2.0.3 + hast-util-to-text: 4.0.2 + import-meta-resolve: 4.2.0 + js-yaml: 4.1.1 + mdast-util-definitions: 6.0.0 + rehype-raw: 7.0.0 + rehype-stringify: 10.0.1 + remark-gfm: 4.0.1 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + remark-smartypants: 3.0.2 + shiki: 3.20.0 + smol-toml: 1.6.0 + unified: 11.0.5 + unist-util-remove-position: 5.0.0 + unist-util-visit: 5.0.0 + unist-util-visit-parents: 6.0.2 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@astrojs/mdx@4.3.13(astro@5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3))': + dependencies: + '@astrojs/markdown-remark': 6.3.10 + '@mdx-js/mdx': 3.1.1 + acorn: 8.15.0 + astro: 5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3) + es-module-lexer: 1.7.0 + estree-util-visit: 2.0.0 + hast-util-to-html: 9.0.5 + piccolore: 0.1.3 + rehype-raw: 7.0.0 + remark-gfm: 4.0.1 + remark-smartypants: 3.0.2 + source-map: 0.7.6 + unist-util-visit: 5.0.0 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@astrojs/prism@3.3.0': + dependencies: + prismjs: 1.30.0 + + '@astrojs/sitemap@3.6.0': + dependencies: + sitemap: 8.0.2 + stream-replace-string: 2.0.0 + zod: 3.25.76 + + '@astrojs/starlight@0.36.3(astro@5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3))': + dependencies: + '@astrojs/markdown-remark': 6.3.10 + '@astrojs/mdx': 4.3.13(astro@5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3)) + '@astrojs/sitemap': 3.6.0 + '@pagefind/default-ui': 1.4.0 + '@types/hast': 3.0.4 + '@types/js-yaml': 4.0.9 + '@types/mdast': 4.0.4 + astro: 5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3) + astro-expressive-code: 0.41.5(astro@5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3)) + bcp-47: 2.1.0 + hast-util-from-html: 2.0.3 + hast-util-select: 6.0.4 + hast-util-to-string: 3.0.1 + hastscript: 9.0.1 + i18next: 23.16.8 + js-yaml: 4.1.1 + klona: 2.0.6 + mdast-util-directive: 3.1.0 + mdast-util-to-markdown: 2.1.2 + mdast-util-to-string: 4.0.0 + pagefind: 1.4.0 + rehype: 13.0.2 + rehype-format: 5.0.1 + remark-directive: 3.0.1 + ultrahtml: 1.6.0 + unified: 11.0.5 + unist-util-visit: 5.0.0 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@astrojs/telemetry@3.3.0': + dependencies: + ci-info: 4.3.1 + debug: 4.4.3 + dlv: 1.1.3 + dset: 3.1.4 + is-docker: 3.0.0 + is-wsl: 3.1.0 + which-pm-runs: 1.1.0 + transitivePeerDependencies: + - supports-color + + '@atproto/api@0.13.35': + dependencies: + '@atproto/common-web': 0.4.7 + '@atproto/lexicon': 0.4.14 + '@atproto/syntax': 0.3.4 + '@atproto/xrpc': 0.6.12 + await-lock: 2.2.2 + multiformats: 9.9.0 + tlds: 1.261.0 + zod: 3.25.76 + + '@atproto/common-web@0.4.7': + dependencies: + '@atproto/lex-data': 0.0.3 + '@atproto/lex-json': 0.0.3 + zod: 3.25.76 + + '@atproto/lex-data@0.0.3': + dependencies: + '@atproto/syntax': 0.4.2 + multiformats: 9.9.0 + tslib: 2.8.1 + uint8arrays: 3.0.0 + unicode-segmenter: 0.14.4 + + '@atproto/lex-json@0.0.3': + dependencies: + '@atproto/lex-data': 0.0.3 + tslib: 2.8.1 + + '@atproto/lexicon@0.4.14': + dependencies: + '@atproto/common-web': 0.4.7 + '@atproto/syntax': 0.4.2 + iso-datestring-validator: 2.2.2 + multiformats: 9.9.0 + zod: 3.25.76 + + '@atproto/syntax@0.3.4': {} + + '@atproto/syntax@0.4.2': {} + + '@atproto/xrpc@0.6.12': + dependencies: + '@atproto/lexicon': 0.4.14 + zod: 3.25.76 + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/parser@7.28.5': + dependencies: + '@babel/types': 7.28.5 + + '@babel/runtime@7.28.4': {} + + '@babel/types@7.28.5': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@braintree/sanitize-url@7.1.1': {} + + '@capsizecss/unpack@3.0.1': + dependencies: + fontkit: 2.0.4 + + '@chevrotain/cst-dts-gen@11.0.3': + dependencies: + '@chevrotain/gast': 11.0.3 + '@chevrotain/types': 11.0.3 + lodash-es: 4.17.21 + + '@chevrotain/gast@11.0.3': + dependencies: + '@chevrotain/types': 11.0.3 + lodash-es: 4.17.21 + + '@chevrotain/regexp-to-ast@11.0.3': {} + + '@chevrotain/types@11.0.3': {} + + '@chevrotain/utils@11.0.3': {} + + '@ctrl/tinycolor@4.2.0': {} + + '@emnapi/runtime@1.7.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@esbuild/aix-ppc64@0.25.12': + optional: true + + '@esbuild/android-arm64@0.25.12': + optional: true + + '@esbuild/android-arm@0.25.12': + optional: true + + '@esbuild/android-x64@0.25.12': + optional: true + + '@esbuild/darwin-arm64@0.25.12': + optional: true + + '@esbuild/darwin-x64@0.25.12': + optional: true + + '@esbuild/freebsd-arm64@0.25.12': + optional: true + + '@esbuild/freebsd-x64@0.25.12': + optional: true + + '@esbuild/linux-arm64@0.25.12': + optional: true + + '@esbuild/linux-arm@0.25.12': + optional: true + + '@esbuild/linux-ia32@0.25.12': + optional: true + + '@esbuild/linux-loong64@0.25.12': + optional: true + + '@esbuild/linux-mips64el@0.25.12': + optional: true + + '@esbuild/linux-ppc64@0.25.12': + optional: true + + '@esbuild/linux-riscv64@0.25.12': + optional: true + + '@esbuild/linux-s390x@0.25.12': + optional: true + + '@esbuild/linux-x64@0.25.12': + optional: true + + '@esbuild/netbsd-arm64@0.25.12': + optional: true + + '@esbuild/netbsd-x64@0.25.12': + optional: true + + '@esbuild/openbsd-arm64@0.25.12': + optional: true + + '@esbuild/openbsd-x64@0.25.12': + optional: true + + '@esbuild/openharmony-arm64@0.25.12': + optional: true + + '@esbuild/sunos-x64@0.25.12': + optional: true + + '@esbuild/win32-arm64@0.25.12': + optional: true + + '@esbuild/win32-ia32@0.25.12': + optional: true + + '@esbuild/win32-x64@0.25.12': + optional: true + + '@expressive-code/core@0.41.5': + dependencies: + '@ctrl/tinycolor': 4.2.0 + hast-util-select: 6.0.4 + hast-util-to-html: 9.0.5 + hast-util-to-text: 4.0.2 + hastscript: 9.0.1 + postcss: 8.5.6 + postcss-nested: 6.2.0(postcss@8.5.6) + unist-util-visit: 5.0.0 + unist-util-visit-parents: 6.0.2 + + '@expressive-code/plugin-frames@0.41.5': + dependencies: + '@expressive-code/core': 0.41.5 + + '@expressive-code/plugin-shiki@0.41.5': + dependencies: + '@expressive-code/core': 0.41.5 + shiki: 3.20.0 + + '@expressive-code/plugin-text-markers@0.41.5': + dependencies: + '@expressive-code/core': 0.41.5 + + '@iconify/types@2.0.0': {} + + '@iconify/utils@3.1.0': + dependencies: + '@antfu/install-pkg': 1.1.0 + '@iconify/types': 2.0.0 + mlly: 1.8.0 + + '@img/colour@1.0.0': {} + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.7.1 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@mdx-js/mdx@3.1.1': + dependencies: + '@types/estree': 1.0.8 + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdx': 2.0.13 + acorn: 8.15.0 + collapse-white-space: 2.1.0 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + estree-util-scope: 1.0.0 + estree-walker: 3.0.3 + hast-util-to-jsx-runtime: 2.3.6 + markdown-extensions: 2.0.0 + recma-build-jsx: 1.0.0 + recma-jsx: 1.0.1(acorn@8.15.0) + recma-stringify: 1.0.0 + rehype-recma: 1.0.0 + remark-mdx: 3.1.1 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + source-map: 0.7.6 + unified: 11.0.5 + unist-util-position-from-estree: 2.0.0 + unist-util-stringify-position: 4.0.0 + unist-util-visit: 5.0.0 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@mermaid-js/parser@0.6.3': + dependencies: + langium: 3.3.1 + + '@oslojs/encoding@1.1.0': {} + + '@pagefind/darwin-arm64@1.4.0': + optional: true + + '@pagefind/darwin-x64@1.4.0': + optional: true + + '@pagefind/default-ui@1.4.0': {} + + '@pagefind/freebsd-x64@1.4.0': + optional: true + + '@pagefind/linux-arm64@1.4.0': + optional: true + + '@pagefind/linux-x64@1.4.0': + optional: true + + '@pagefind/windows-x64@1.4.0': + optional: true + + '@pasqal-io/starlight-client-mermaid@0.1.0(@astrojs/markdown-remark@6.3.10)(@astrojs/starlight@0.36.3(astro@5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3)))': + dependencies: + '@astrojs/markdown-remark': 6.3.10 + '@astrojs/starlight': 0.36.3(astro@5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3)) + mermaid: 11.12.2 + unist-util-visit: 5.0.0 + + '@rollup/pluginutils@5.3.0(rollup@4.54.0)': + dependencies: + '@types/estree': 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.3 + optionalDependencies: + rollup: 4.54.0 + + '@rollup/rollup-android-arm-eabi@4.54.0': + optional: true + + '@rollup/rollup-android-arm64@4.54.0': + optional: true + + '@rollup/rollup-darwin-arm64@4.54.0': + optional: true + + '@rollup/rollup-darwin-x64@4.54.0': + optional: true + + '@rollup/rollup-freebsd-arm64@4.54.0': + optional: true + + '@rollup/rollup-freebsd-x64@4.54.0': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.54.0': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.54.0': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.54.0': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.54.0': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.54.0': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.54.0': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.54.0': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.54.0': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.54.0': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.54.0': + optional: true + + '@rollup/rollup-linux-x64-musl@4.54.0': + optional: true + + '@rollup/rollup-openharmony-arm64@4.54.0': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.54.0': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.54.0': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.54.0': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.54.0': + optional: true + + '@shikijs/core@3.20.0': + dependencies: + '@shikijs/types': 3.20.0 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.5 + + '@shikijs/engine-javascript@3.20.0': + dependencies: + '@shikijs/types': 3.20.0 + '@shikijs/vscode-textmate': 10.0.2 + oniguruma-to-es: 4.3.4 + + '@shikijs/engine-oniguruma@3.20.0': + dependencies: + '@shikijs/types': 3.20.0 + '@shikijs/vscode-textmate': 10.0.2 + + '@shikijs/langs@3.20.0': + dependencies: + '@shikijs/types': 3.20.0 + + '@shikijs/themes@3.20.0': + dependencies: + '@shikijs/types': 3.20.0 + + '@shikijs/types@3.20.0': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + '@shikijs/vscode-textmate@10.0.2': {} + + '@swc/helpers@0.5.18': + dependencies: + tslib: 2.8.1 + + '@types/d3-array@3.2.2': {} + + '@types/d3-axis@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-brush@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-chord@3.0.6': {} + + '@types/d3-color@3.1.3': {} + + '@types/d3-contour@3.0.6': + dependencies: + '@types/d3-array': 3.2.2 + '@types/geojson': 7946.0.16 + + '@types/d3-delaunay@6.0.4': {} + + '@types/d3-dispatch@3.0.7': {} + + '@types/d3-drag@3.0.7': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-dsv@3.0.7': {} + + '@types/d3-ease@3.0.2': {} + + '@types/d3-fetch@3.0.7': + dependencies: + '@types/d3-dsv': 3.0.7 + + '@types/d3-force@3.0.10': {} + + '@types/d3-format@3.0.4': {} + + '@types/d3-geo@3.1.0': + dependencies: + '@types/geojson': 7946.0.16 + + '@types/d3-hierarchy@3.1.7': {} + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-path@3.1.1': {} + + '@types/d3-polygon@3.0.2': {} + + '@types/d3-quadtree@3.0.6': {} + + '@types/d3-random@3.0.3': {} + + '@types/d3-scale-chromatic@3.1.0': {} + + '@types/d3-scale@4.0.9': + dependencies: + '@types/d3-time': 3.0.4 + + '@types/d3-selection@3.0.11': {} + + '@types/d3-shape@3.1.7': + dependencies: + '@types/d3-path': 3.1.1 + + '@types/d3-time-format@4.0.3': {} + + '@types/d3-time@3.0.4': {} + + '@types/d3-timer@3.0.2': {} + + '@types/d3-transition@3.0.9': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-zoom@3.0.8': + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + + '@types/d3@7.4.3': + dependencies: + '@types/d3-array': 3.2.2 + '@types/d3-axis': 3.0.6 + '@types/d3-brush': 3.0.6 + '@types/d3-chord': 3.0.6 + '@types/d3-color': 3.1.3 + '@types/d3-contour': 3.0.6 + '@types/d3-delaunay': 6.0.4 + '@types/d3-dispatch': 3.0.7 + '@types/d3-drag': 3.0.7 + '@types/d3-dsv': 3.0.7 + '@types/d3-ease': 3.0.2 + '@types/d3-fetch': 3.0.7 + '@types/d3-force': 3.0.10 + '@types/d3-format': 3.0.4 + '@types/d3-geo': 3.1.0 + '@types/d3-hierarchy': 3.1.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-path': 3.1.1 + '@types/d3-polygon': 3.0.2 + '@types/d3-quadtree': 3.0.6 + '@types/d3-random': 3.0.3 + '@types/d3-scale': 4.0.9 + '@types/d3-scale-chromatic': 3.1.0 + '@types/d3-selection': 3.0.11 + '@types/d3-shape': 3.1.7 + '@types/d3-time': 3.0.4 + '@types/d3-time-format': 4.0.3 + '@types/d3-timer': 3.0.2 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + + '@types/debug@4.1.12': + dependencies: + '@types/ms': 2.1.0 + + '@types/estree-jsx@1.0.5': + dependencies: + '@types/estree': 1.0.8 + + '@types/estree@1.0.8': {} + + '@types/fontkit@2.0.8': + dependencies: + '@types/node': 25.0.3 + + '@types/geojson@7946.0.16': {} + + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/js-yaml@4.0.9': {} + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/mdx@2.0.13': {} + + '@types/ms@2.1.0': {} + + '@types/nlcst@2.0.3': + dependencies: + '@types/unist': 3.0.3 + + '@types/node-fetch@2.6.13': + dependencies: + '@types/node': 18.19.130 + form-data: 4.0.5 + + '@types/node@17.0.45': {} + + '@types/node@18.19.130': + dependencies: + undici-types: 5.26.5 + + '@types/node@25.0.3': + dependencies: + undici-types: 7.16.0 + + '@types/sax@1.2.7': + dependencies: + '@types/node': 17.0.45 + + '@types/trusted-types@2.0.7': + optional: true + + '@types/unist@2.0.11': {} + + '@types/unist@3.0.3': {} + + '@ungap/structured-clone@1.3.0': {} + + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + + acorn-jsx@5.3.2(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + + acorn@8.15.0: {} + + agentkeepalive@4.6.0: + dependencies: + humanize-ms: 1.2.1 + + ansi-align@3.0.1: + dependencies: + string-width: 4.2.3 + + ansi-regex@5.0.1: {} + + ansi-regex@6.2.2: {} + + ansi-styles@6.2.3: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + arg@5.0.2: {} + + argparse@2.0.1: {} + + aria-query@5.3.2: {} + + array-iterate@2.0.1: {} + + astring@1.9.0: {} + + astro-auto-import@0.4.5(astro@5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3)): + dependencies: + '@types/node': 18.19.130 + acorn: 8.15.0 + astro: 5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3) + + astro-embed@0.9.2(astro@5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3)): + dependencies: + '@astro-community/astro-embed-baseline-status': 0.2.1(astro@5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3)) + '@astro-community/astro-embed-bluesky': 0.1.5(astro@5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3)) + '@astro-community/astro-embed-integration': 0.8.3(astro@5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3)) + '@astro-community/astro-embed-link-preview': 0.2.3 + '@astro-community/astro-embed-twitter': 0.5.9(astro@5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3)) + '@astro-community/astro-embed-vimeo': 0.3.11(astro@5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3)) + '@astro-community/astro-embed-youtube': 0.5.9(astro@5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3)) + astro: 5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3) + transitivePeerDependencies: + - canvas + + astro-expressive-code@0.41.5(astro@5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3)): + dependencies: + astro: 5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3) + rehype-expressive-code: 0.41.5 + + astro@5.16.6(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3): + dependencies: + '@astrojs/compiler': 2.13.0 + '@astrojs/internal-helpers': 0.7.5 + '@astrojs/markdown-remark': 6.3.10 + '@astrojs/telemetry': 3.3.0 + '@capsizecss/unpack': 3.0.1 + '@oslojs/encoding': 1.1.0 + '@rollup/pluginutils': 5.3.0(rollup@4.54.0) + acorn: 8.15.0 + aria-query: 5.3.2 + axobject-query: 4.1.0 + boxen: 8.0.1 + ci-info: 4.3.1 + clsx: 2.1.1 + common-ancestor-path: 1.0.1 + cookie: 1.1.1 + cssesc: 3.0.0 + debug: 4.4.3 + deterministic-object-hash: 2.0.2 + devalue: 5.6.1 + diff: 5.2.0 + dlv: 1.1.3 + dset: 3.1.4 + es-module-lexer: 1.7.0 + esbuild: 0.25.12 + estree-walker: 3.0.3 + flattie: 1.1.1 + fontace: 0.3.1 + github-slugger: 2.0.0 + html-escaper: 3.0.3 + http-cache-semantics: 4.2.0 + import-meta-resolve: 4.2.0 + js-yaml: 4.1.1 + magic-string: 0.30.21 + magicast: 0.5.1 + mrmime: 2.0.1 + neotraverse: 0.6.18 + p-limit: 6.2.0 + p-queue: 8.1.1 + package-manager-detector: 1.6.0 + piccolore: 0.1.3 + picomatch: 4.0.3 + prompts: 2.4.2 + rehype: 13.0.2 + semver: 7.7.3 + shiki: 3.20.0 + smol-toml: 1.6.0 + svgo: 4.0.0 + tinyexec: 1.0.2 + tinyglobby: 0.2.15 + tsconfck: 3.1.6(typescript@5.9.3) + ultrahtml: 1.6.0 + unifont: 0.6.0 + unist-util-visit: 5.0.0 + unstorage: 1.17.3 + vfile: 6.0.3 + vite: 6.4.1(@types/node@25.0.3) + vitefu: 1.1.1(vite@6.4.1(@types/node@25.0.3)) + xxhash-wasm: 1.1.0 + yargs-parser: 21.1.1 + yocto-spinner: 0.2.3 + zod: 3.25.76 + zod-to-json-schema: 3.25.0(zod@3.25.76) + zod-to-ts: 1.2.0(typescript@5.9.3)(zod@3.25.76) + optionalDependencies: + sharp: 0.34.5 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@types/node' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - db0 + - idb-keyval + - ioredis + - jiti + - less + - lightningcss + - rollup + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - typescript + - uploadthing + - yaml + + asynckit@0.4.0: {} + + await-lock@2.2.2: {} + + axobject-query@4.1.0: {} + + bail@2.0.2: {} + + base-64@1.0.0: {} + + base64-js@1.5.1: {} + + bcp-47-match@2.0.3: {} + + bcp-47@2.1.0: + dependencies: + is-alphabetical: 2.0.1 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + + boolbase@1.0.0: {} + + boxen@8.0.1: + dependencies: + ansi-align: 3.0.1 + camelcase: 8.0.0 + chalk: 5.6.2 + cli-boxes: 3.0.0 + string-width: 7.2.0 + type-fest: 4.41.0 + widest-line: 5.0.0 + wrap-ansi: 9.0.2 + + brotli@1.3.3: + dependencies: + base64-js: 1.5.1 + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + camelcase@8.0.0: {} + + ccount@2.0.1: {} + + chalk@5.6.2: {} + + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + character-reference-invalid@2.0.1: {} + + chevrotain-allstar@0.3.1(chevrotain@11.0.3): + dependencies: + chevrotain: 11.0.3 + lodash-es: 4.17.22 + + chevrotain@11.0.3: + dependencies: + '@chevrotain/cst-dts-gen': 11.0.3 + '@chevrotain/gast': 11.0.3 + '@chevrotain/regexp-to-ast': 11.0.3 + '@chevrotain/types': 11.0.3 + '@chevrotain/utils': 11.0.3 + lodash-es: 4.17.21 + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + + ci-info@4.3.1: {} + + cli-boxes@3.0.0: {} + + clone@2.1.2: {} + + clsx@2.1.1: {} + + collapse-white-space@2.1.0: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + comma-separated-tokens@2.0.3: {} + + commander@11.1.0: {} + + commander@7.2.0: {} + + commander@8.3.0: {} + + common-ancestor-path@1.0.1: {} + + confbox@0.1.8: {} + + cookie-es@1.2.2: {} + + cookie@1.1.1: {} + + cose-base@1.0.3: + dependencies: + layout-base: 1.0.2 + + cose-base@2.2.0: + dependencies: + layout-base: 2.0.1 + + crossws@0.3.5: + dependencies: + uncrypto: 0.1.3 + + css-select@5.2.2: + dependencies: + boolbase: 1.0.0 + css-what: 6.2.2 + domhandler: 5.0.3 + domutils: 3.2.2 + nth-check: 2.1.1 + + css-selector-parser@1.4.1: {} + + css-selector-parser@3.3.0: {} + + css-tree@2.2.1: + dependencies: + mdn-data: 2.0.28 + source-map-js: 1.2.1 + + css-tree@3.1.0: + dependencies: + mdn-data: 2.12.2 + source-map-js: 1.2.1 + + css-what@6.2.2: {} + + cssesc@3.0.0: {} + + csso@5.0.5: + dependencies: + css-tree: 2.2.1 + + cssom@0.5.0: {} + + cytoscape-cose-bilkent@4.1.0(cytoscape@3.33.1): + dependencies: + cose-base: 1.0.3 + cytoscape: 3.33.1 + + cytoscape-fcose@2.2.0(cytoscape@3.33.1): + dependencies: + cose-base: 2.2.0 + cytoscape: 3.33.1 + + cytoscape@3.33.1: {} + + d3-array@2.12.1: + dependencies: + internmap: 1.0.1 + + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + + d3-axis@3.0.0: {} + + d3-brush@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3-chord@3.0.1: + dependencies: + d3-path: 3.1.0 + + d3-color@3.1.0: {} + + d3-contour@4.0.2: + dependencies: + d3-array: 3.2.4 + + d3-delaunay@6.0.4: + dependencies: + delaunator: 5.0.1 + + d3-dispatch@3.0.1: {} + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + + d3-dsv@3.0.1: + dependencies: + commander: 7.2.0 + iconv-lite: 0.6.3 + rw: 1.3.3 + + d3-ease@3.0.1: {} + + d3-fetch@3.0.1: + dependencies: + d3-dsv: 3.0.1 + + d3-force@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + + d3-format@3.1.0: {} + + d3-geo@3.1.1: + dependencies: + d3-array: 3.2.4 + + d3-hierarchy@3.1.2: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-path@1.0.9: {} + + d3-path@3.1.0: {} + + d3-polygon@3.0.1: {} + + d3-quadtree@3.0.1: {} + + d3-random@3.0.1: {} + + d3-sankey@0.12.3: + dependencies: + d3-array: 2.12.1 + d3-shape: 1.3.7 + + d3-scale-chromatic@3.1.0: + dependencies: + d3-color: 3.1.0 + d3-interpolate: 3.0.1 + + d3-scale@4.0.2: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.0 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + + d3-selection@3.0.0: {} + + d3-shape@1.3.7: + dependencies: + d3-path: 1.0.9 + + d3-shape@3.2.0: + dependencies: + d3-path: 3.1.0 + + d3-time-format@4.1.0: + dependencies: + d3-time: 3.1.0 + + d3-time@3.1.0: + dependencies: + d3-array: 3.2.4 + + d3-timer@3.0.1: {} + + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3@7.9.0: + dependencies: + d3-array: 3.2.4 + d3-axis: 3.0.0 + d3-brush: 3.0.0 + d3-chord: 3.0.1 + d3-color: 3.1.0 + d3-contour: 4.0.2 + d3-delaunay: 6.0.4 + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-dsv: 3.0.1 + d3-ease: 3.0.1 + d3-fetch: 3.0.1 + d3-force: 3.0.0 + d3-format: 3.1.0 + d3-geo: 3.1.1 + d3-hierarchy: 3.1.2 + d3-interpolate: 3.0.1 + d3-path: 3.1.0 + d3-polygon: 3.0.1 + d3-quadtree: 3.0.1 + d3-random: 3.0.1 + d3-scale: 4.0.2 + d3-scale-chromatic: 3.1.0 + d3-selection: 3.0.0 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + d3-timer: 3.0.1 + d3-transition: 3.0.1(d3-selection@3.0.0) + d3-zoom: 3.0.0 + + dagre-d3-es@7.0.13: + dependencies: + d3: 7.9.0 + lodash-es: 4.17.22 + + dayjs@1.11.19: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decode-named-character-reference@1.2.0: + dependencies: + character-entities: 2.0.2 + + defu@6.1.4: {} + + delaunator@5.0.1: + dependencies: + robust-predicates: 3.0.2 + + delayed-stream@1.0.0: {} + + dequal@2.0.3: {} + + destr@2.0.5: {} + + detect-libc@2.1.2: {} + + deterministic-object-hash@2.0.2: + dependencies: + base-64: 1.0.0 + + devalue@5.6.1: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + dfa@1.2.0: {} + + diff@5.2.0: {} + + direction@2.0.1: {} + + dlv@1.1.3: {} + + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + + domelementtype@2.3.0: {} + + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + + dompurify@3.3.1: + optionalDependencies: + '@types/trusted-types': 2.0.7 + + domutils@3.2.2: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + + dset@3.1.4: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + emoji-regex@10.6.0: {} + + emoji-regex@8.0.0: {} + + entities@4.5.0: {} + + entities@6.0.1: {} + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-module-lexer@1.7.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + esast-util-from-estree@2.0.0: + dependencies: + '@types/estree-jsx': 1.0.5 + devlop: 1.1.0 + estree-util-visit: 2.0.0 + unist-util-position-from-estree: 2.0.0 + + esast-util-from-js@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + acorn: 8.15.0 + esast-util-from-estree: 2.0.0 + vfile-message: 4.0.3 + + esbuild@0.25.12: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 + + escape-string-regexp@5.0.0: {} + + estree-util-attach-comments@3.0.0: + dependencies: + '@types/estree': 1.0.8 + + estree-util-build-jsx@3.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + estree-walker: 3.0.3 + + estree-util-is-identifier-name@3.0.0: {} + + estree-util-scope@1.0.0: + dependencies: + '@types/estree': 1.0.8 + devlop: 1.1.0 + + estree-util-to-js@2.0.0: + dependencies: + '@types/estree-jsx': 1.0.5 + astring: 1.9.0 + source-map: 0.7.6 + + estree-util-visit@2.0.0: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/unist': 3.0.3 + + estree-walker@2.0.2: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + + event-target-shim@5.0.1: {} + + eventemitter3@5.0.1: {} + + expressive-code@0.41.5: + dependencies: + '@expressive-code/core': 0.41.5 + '@expressive-code/plugin-frames': 0.41.5 + '@expressive-code/plugin-shiki': 0.41.5 + '@expressive-code/plugin-text-markers': 0.41.5 + + extend@3.0.2: {} + + fast-deep-equal@3.1.3: {} + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + flattie@1.1.1: {} + + fontace@0.3.1: + dependencies: + '@types/fontkit': 2.0.8 + fontkit: 2.0.4 + + fontkit@2.0.4: + dependencies: + '@swc/helpers': 0.5.18 + brotli: 1.3.3 + clone: 2.1.2 + dfa: 1.2.0 + fast-deep-equal: 3.1.3 + restructure: 3.0.2 + tiny-inflate: 1.0.3 + unicode-properties: 1.4.1 + unicode-trie: 2.0.0 + + form-data-encoder@1.7.2: {} + + form-data@4.0.5: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + + formdata-node@4.4.1: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 4.0.0-beta.3 + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + get-east-asian-width@1.4.0: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + github-slugger@2.0.0: {} + + gopd@1.2.0: {} + + h3@1.15.4: + dependencies: + cookie-es: 1.2.2 + crossws: 0.3.5 + defu: 6.1.4 + destr: 2.0.5 + iron-webcrypto: 1.2.1 + node-mock-http: 1.0.4 + radix3: 1.1.2 + ufo: 1.6.1 + uncrypto: 0.1.3 + + hachure-fill@0.5.2: {} + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + hast-util-embedded@3.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-is-element: 3.0.0 + + hast-util-format@1.1.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-embedded: 3.0.0 + hast-util-minify-whitespace: 1.0.1 + hast-util-phrasing: 3.0.1 + hast-util-whitespace: 3.0.0 + html-whitespace-sensitive-tag-names: 3.0.1 + unist-util-visit-parents: 6.0.2 + + hast-util-from-html@2.0.3: + dependencies: + '@types/hast': 3.0.4 + devlop: 1.1.0 + hast-util-from-parse5: 8.0.3 + parse5: 7.3.0 + vfile: 6.0.3 + vfile-message: 4.0.3 + + hast-util-from-parse5@8.0.3: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + devlop: 1.1.0 + hastscript: 9.0.1 + property-information: 7.1.0 + vfile: 6.0.3 + vfile-location: 5.0.3 + web-namespaces: 2.0.1 + + hast-util-has-property@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-is-body-ok-link@3.0.1: + dependencies: + '@types/hast': 3.0.4 + + hast-util-is-element@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-minify-whitespace@1.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-embedded: 3.0.0 + hast-util-is-element: 3.0.0 + hast-util-whitespace: 3.0.0 + unist-util-is: 6.0.1 + + hast-util-parse-selector@4.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-phrasing@3.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-embedded: 3.0.0 + hast-util-has-property: 3.0.0 + hast-util-is-body-ok-link: 3.0.1 + hast-util-is-element: 3.0.0 + + hast-util-raw@9.1.0: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + '@ungap/structured-clone': 1.3.0 + hast-util-from-parse5: 8.0.3 + hast-util-to-parse5: 8.0.1 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + parse5: 7.3.0 + unist-util-position: 5.0.0 + unist-util-visit: 5.0.0 + vfile: 6.0.3 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + + hast-util-select@6.0.4: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + bcp-47-match: 2.0.3 + comma-separated-tokens: 2.0.3 + css-selector-parser: 3.3.0 + devlop: 1.1.0 + direction: 2.0.1 + hast-util-has-property: 3.0.0 + hast-util-to-string: 3.0.1 + hast-util-whitespace: 3.0.0 + nth-check: 2.1.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + unist-util-visit: 5.0.0 + zwitch: 2.0.4 + + hast-util-to-estree@3.1.3: + dependencies: + '@types/estree': 1.0.8 + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + estree-util-attach-comments: 3.0.0 + estree-util-is-identifier-name: 3.0.0 + hast-util-whitespace: 3.0.0 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + style-to-js: 1.1.21 + unist-util-position: 5.0.0 + zwitch: 2.0.4 + transitivePeerDependencies: + - supports-color + + hast-util-to-html@9.0.5: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 + + hast-util-to-jsx-runtime@2.3.6: + dependencies: + '@types/estree': 1.0.8 + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + hast-util-whitespace: 3.0.0 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + style-to-js: 1.1.21 + unist-util-position: 5.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + hast-util-to-parse5@8.0.1: + dependencies: + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + + hast-util-to-string@3.0.1: + dependencies: + '@types/hast': 3.0.4 + + hast-util-to-text@4.0.2: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + hast-util-is-element: 3.0.0 + unist-util-find-after: 5.0.0 + + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hastscript@9.0.1: + dependencies: + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + hast-util-parse-selector: 4.0.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + + html-escaper@3.0.3: {} + + html-void-elements@3.0.0: {} + + html-whitespace-sensitive-tag-names@3.0.1: {} + + htmlparser2@10.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + entities: 6.0.1 + + http-cache-semantics@4.2.0: {} + + humanize-ms@1.2.1: + dependencies: + ms: 2.1.3 + + i18next@23.16.8: + dependencies: + '@babel/runtime': 7.28.4 + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + + import-meta-resolve@4.2.0: {} + + inline-style-parser@0.2.7: {} + + internmap@1.0.1: {} + + internmap@2.0.3: {} + + iron-webcrypto@1.2.1: {} + + is-alphabetical@2.0.1: {} + + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + + is-decimal@2.0.1: {} + + is-docker@3.0.0: {} + + is-fullwidth-code-point@3.0.0: {} + + is-hexadecimal@2.0.1: {} + + is-inside-container@1.0.0: + dependencies: + is-docker: 3.0.0 + + is-plain-obj@4.1.0: {} + + is-wsl@3.1.0: + dependencies: + is-inside-container: 1.0.0 + + iso-datestring-validator@2.2.2: {} + + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + katex@0.16.27: + dependencies: + commander: 8.3.0 + + khroma@2.1.0: {} + + kleur@3.0.3: {} + + klona@2.0.6: {} + + langium@3.3.1: + dependencies: + chevrotain: 11.0.3 + chevrotain-allstar: 0.3.1(chevrotain@11.0.3) + vscode-languageserver: 9.0.1 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.0.8 + + layout-base@1.0.2: {} + + layout-base@2.0.1: {} + + linkedom@0.18.12: + dependencies: + css-select: 5.2.2 + cssom: 0.5.0 + html-escaper: 3.0.3 + htmlparser2: 10.0.0 + uhyphen: 0.2.0 + + lite-youtube-embed@0.3.4: {} + + lodash-es@4.17.21: {} + + lodash-es@4.17.22: {} + + longest-streak@3.1.0: {} + + lru-cache@10.4.3: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + magicast@0.5.1: + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + source-map-js: 1.2.1 + + markdown-extensions@2.0.0: {} + + markdown-table@3.0.4: {} + + marked@16.4.2: {} + + math-intrinsics@1.1.0: {} + + mdast-util-definitions@6.0.0: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + unist-util-visit: 5.0.0 + + mdast-util-directive@3.1.0: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-visit-parents: 6.0.2 + transitivePeerDependencies: + - supports-color + + mdast-util-find-and-replace@3.0.2: + dependencies: + '@types/mdast': 4.0.4 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + mdast-util-from-markdown@2.0.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-autolink-literal@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.2 + micromark-util-character: 2.1.1 + + mdast-util-gfm-footnote@2.1.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + micromark-util-normalize-identifier: 2.0.1 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-strikethrough@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-table@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-task-list-item@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm@3.1.0: + dependencies: + mdast-util-from-markdown: 2.0.2 + mdast-util-gfm-autolink-literal: 2.0.1 + mdast-util-gfm-footnote: 2.1.0 + mdast-util-gfm-strikethrough: 2.0.0 + mdast-util-gfm-table: 2.0.0 + mdast-util-gfm-task-list-item: 2.0.0 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-expression@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-jsx@3.2.0: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx@3.0.0: + dependencies: + mdast-util-from-markdown: 2.0.2 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdxjs-esm@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.1 + + mdast-util-to-hast@13.2.1: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.0 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.1 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.0.0 + vfile: 6.0.3 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.0.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + + mdn-data@2.0.28: {} + + mdn-data@2.12.2: {} + + mermaid@11.12.2: + dependencies: + '@braintree/sanitize-url': 7.1.1 + '@iconify/utils': 3.1.0 + '@mermaid-js/parser': 0.6.3 + '@types/d3': 7.4.3 + cytoscape: 3.33.1 + cytoscape-cose-bilkent: 4.1.0(cytoscape@3.33.1) + cytoscape-fcose: 2.2.0(cytoscape@3.33.1) + d3: 7.9.0 + d3-sankey: 0.12.3 + dagre-d3-es: 7.0.13 + dayjs: 1.11.19 + dompurify: 3.3.1 + katex: 0.16.27 + khroma: 2.1.0 + lodash-es: 4.17.22 + marked: 16.4.2 + roughjs: 4.6.6 + stylis: 4.3.6 + ts-dedent: 2.2.0 + uuid: 11.1.0 + + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-directive@3.0.2: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + parse-entities: 4.0.2 + + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-strikethrough@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-table@2.1.1: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-tagfilter@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-gfm-task-list-item@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm@3.0.0: + dependencies: + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-strikethrough: 2.1.0 + micromark-extension-gfm-table: 2.1.1 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.1.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-mdx-expression@3.0.1: + dependencies: + '@types/estree': 1.0.8 + devlop: 1.1.0 + micromark-factory-mdx-expression: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-mdx-jsx@3.0.2: + dependencies: + '@types/estree': 1.0.8 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + micromark-factory-mdx-expression: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + vfile-message: 4.0.3 + + micromark-extension-mdx-md@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-mdxjs-esm@3.0.0: + dependencies: + '@types/estree': 1.0.8 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-position-from-estree: 2.0.0 + vfile-message: 4.0.3 + + micromark-extension-mdxjs@3.0.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + micromark-extension-mdx-expression: 3.0.1 + micromark-extension-mdx-jsx: 3.0.2 + micromark-extension-mdx-md: 2.0.0 + micromark-extension-mdxjs-esm: 3.0.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-mdx-expression@2.0.3: + dependencies: + '@types/estree': 1.0.8 + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-position-from-estree: 2.0.0 + vfile-message: 4.0.3 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.2.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-events-to-acorn@2.0.3: + dependencies: + '@types/estree': 1.0.8 + '@types/unist': 3.0.3 + devlop: 1.1.0 + estree-util-visit: 2.0.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + vfile-message: 4.0.3 + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.12 + debug: 4.4.3 + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mlly@1.8.0: + dependencies: + acorn: 8.15.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.1 + + mrmime@2.0.1: {} + + ms@2.1.3: {} + + multiformats@9.9.0: {} + + nanoid@3.3.11: {} + + neotraverse@0.6.18: {} + + nlcst-to-string@4.0.0: + dependencies: + '@types/nlcst': 2.0.3 + + node-domexception@1.0.0: {} + + node-fetch-native@1.6.7: {} + + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + + node-mock-http@1.0.4: {} + + normalize-path@3.0.0: {} + + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + + ofetch@1.5.1: + dependencies: + destr: 2.0.5 + node-fetch-native: 1.6.7 + ufo: 1.6.1 + + ohash@2.0.11: {} + + oniguruma-parser@0.12.1: {} + + oniguruma-to-es@4.3.4: + dependencies: + oniguruma-parser: 0.12.1 + regex: 6.1.0 + regex-recursion: 6.0.2 + + openai@4.104.0(zod@3.25.76): + dependencies: + '@types/node': 18.19.130 + '@types/node-fetch': 2.6.13 + abort-controller: 3.0.0 + agentkeepalive: 4.6.0 + form-data-encoder: 1.7.2 + formdata-node: 4.4.1 + node-fetch: 2.7.0 + optionalDependencies: + zod: 3.25.76 + transitivePeerDependencies: + - encoding + + p-limit@6.2.0: + dependencies: + yocto-queue: 1.2.2 + + p-queue@8.1.1: + dependencies: + eventemitter3: 5.0.1 + p-timeout: 6.1.4 + + p-timeout@6.1.4: {} + + package-manager-detector@1.6.0: {} + + pagefind@1.4.0: + optionalDependencies: + '@pagefind/darwin-arm64': 1.4.0 + '@pagefind/darwin-x64': 1.4.0 + '@pagefind/freebsd-x64': 1.4.0 + '@pagefind/linux-arm64': 1.4.0 + '@pagefind/linux-x64': 1.4.0 + '@pagefind/windows-x64': 1.4.0 + + pako@0.2.9: {} + + parse-entities@4.0.2: + dependencies: + '@types/unist': 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.2.0 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + + parse-latin@7.0.0: + dependencies: + '@types/nlcst': 2.0.3 + '@types/unist': 3.0.3 + nlcst-to-string: 4.0.0 + unist-util-modify-children: 4.0.0 + unist-util-visit-children: 3.0.0 + vfile: 6.0.3 + + parse5@7.3.0: + dependencies: + entities: 6.0.1 + + path-data-parser@0.1.0: {} + + pathe@2.0.3: {} + + piccolore@0.1.3: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.3: {} + + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.0 + pathe: 2.0.3 + + points-on-curve@0.2.0: {} + + points-on-path@0.2.1: + dependencies: + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + + postcss-nested@6.2.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 6.1.2 + + postcss-selector-parser@6.1.2: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prismjs@1.30.0: {} + + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + + property-information@7.1.0: {} + + radix3@1.1.2: {} + + readdirp@4.1.2: {} + + recma-build-jsx@1.0.0: + dependencies: + '@types/estree': 1.0.8 + estree-util-build-jsx: 3.0.1 + vfile: 6.0.3 + + recma-jsx@1.0.1(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + estree-util-to-js: 2.0.0 + recma-parse: 1.0.0 + recma-stringify: 1.0.0 + unified: 11.0.5 + + recma-parse@1.0.0: + dependencies: + '@types/estree': 1.0.8 + esast-util-from-js: 2.0.1 + unified: 11.0.5 + vfile: 6.0.3 + + recma-stringify@1.0.0: + dependencies: + '@types/estree': 1.0.8 + estree-util-to-js: 2.0.0 + unified: 11.0.5 + vfile: 6.0.3 + + regex-recursion@6.0.2: + dependencies: + regex-utilities: 2.3.0 + + regex-utilities@2.3.0: {} + + regex@6.1.0: + dependencies: + regex-utilities: 2.3.0 + + rehype-expressive-code@0.41.5: + dependencies: + expressive-code: 0.41.5 + + rehype-format@5.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-format: 1.1.0 + + rehype-parse@9.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-from-html: 2.0.3 + unified: 11.0.5 + + rehype-raw@7.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-raw: 9.1.0 + vfile: 6.0.3 + + rehype-recma@1.0.0: + dependencies: + '@types/estree': 1.0.8 + '@types/hast': 3.0.4 + hast-util-to-estree: 3.1.3 + transitivePeerDependencies: + - supports-color + + rehype-stringify@10.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.5 + unified: 11.0.5 + + rehype@13.0.2: + dependencies: + '@types/hast': 3.0.4 + rehype-parse: 9.0.1 + rehype-stringify: 10.0.1 + unified: 11.0.5 + + remark-directive@3.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-directive: 3.1.0 + micromark-extension-directive: 3.0.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-gfm@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-gfm: 3.1.0 + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-mdx@3.1.1: + dependencies: + mdast-util-mdx: 3.0.0 + micromark-extension-mdxjs: 3.0.0 + transitivePeerDependencies: + - supports-color + + remark-parse@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.2 + micromark-util-types: 2.0.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-rehype@11.1.2: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + mdast-util-to-hast: 13.2.1 + unified: 11.0.5 + vfile: 6.0.3 + + remark-smartypants@3.0.2: + dependencies: + retext: 9.0.0 + retext-smartypants: 6.2.0 + unified: 11.0.5 + unist-util-visit: 5.0.0 + + remark-stringify@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-to-markdown: 2.1.2 + unified: 11.0.5 + + restructure@3.0.2: {} + + retext-latin@4.0.0: + dependencies: + '@types/nlcst': 2.0.3 + parse-latin: 7.0.0 + unified: 11.0.5 + + retext-smartypants@6.2.0: + dependencies: + '@types/nlcst': 2.0.3 + nlcst-to-string: 4.0.0 + unist-util-visit: 5.0.0 + + retext-stringify@4.0.0: + dependencies: + '@types/nlcst': 2.0.3 + nlcst-to-string: 4.0.0 + unified: 11.0.5 + + retext@9.0.0: + dependencies: + '@types/nlcst': 2.0.3 + retext-latin: 4.0.0 + retext-stringify: 4.0.0 + unified: 11.0.5 + + robust-predicates@3.0.2: {} + + rollup@4.54.0: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.54.0 + '@rollup/rollup-android-arm64': 4.54.0 + '@rollup/rollup-darwin-arm64': 4.54.0 + '@rollup/rollup-darwin-x64': 4.54.0 + '@rollup/rollup-freebsd-arm64': 4.54.0 + '@rollup/rollup-freebsd-x64': 4.54.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.54.0 + '@rollup/rollup-linux-arm-musleabihf': 4.54.0 + '@rollup/rollup-linux-arm64-gnu': 4.54.0 + '@rollup/rollup-linux-arm64-musl': 4.54.0 + '@rollup/rollup-linux-loong64-gnu': 4.54.0 + '@rollup/rollup-linux-ppc64-gnu': 4.54.0 + '@rollup/rollup-linux-riscv64-gnu': 4.54.0 + '@rollup/rollup-linux-riscv64-musl': 4.54.0 + '@rollup/rollup-linux-s390x-gnu': 4.54.0 + '@rollup/rollup-linux-x64-gnu': 4.54.0 + '@rollup/rollup-linux-x64-musl': 4.54.0 + '@rollup/rollup-openharmony-arm64': 4.54.0 + '@rollup/rollup-win32-arm64-msvc': 4.54.0 + '@rollup/rollup-win32-ia32-msvc': 4.54.0 + '@rollup/rollup-win32-x64-gnu': 4.54.0 + '@rollup/rollup-win32-x64-msvc': 4.54.0 + fsevents: 2.3.3 + + roughjs@4.6.6: + dependencies: + hachure-fill: 0.5.2 + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + points-on-path: 0.2.1 + + rw@1.3.3: {} + + safer-buffer@2.1.2: {} + + sax@1.4.3: {} + + semver@7.7.3: {} + + sharp@0.34.5: + dependencies: + '@img/colour': 1.0.0 + detect-libc: 2.1.2 + semver: 7.7.3 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + + shiki@3.20.0: + dependencies: + '@shikijs/core': 3.20.0 + '@shikijs/engine-javascript': 3.20.0 + '@shikijs/engine-oniguruma': 3.20.0 + '@shikijs/langs': 3.20.0 + '@shikijs/themes': 3.20.0 + '@shikijs/types': 3.20.0 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + sisteransi@1.0.5: {} + + sitemap@8.0.2: + dependencies: + '@types/node': 17.0.45 + '@types/sax': 1.2.7 + arg: 5.0.2 + sax: 1.4.3 + + smol-toml@1.6.0: {} + + source-map-js@1.2.1: {} + + source-map@0.7.6: {} + + space-separated-tokens@2.0.2: {} + + stream-replace-string@2.0.0: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@7.2.0: + dependencies: + emoji-regex: 10.6.0 + get-east-asian-width: 1.4.0 + strip-ansi: 7.1.2 + + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.2: + dependencies: + ansi-regex: 6.2.2 + + style-to-js@1.1.21: + dependencies: + style-to-object: 1.0.14 + + style-to-object@1.0.14: + dependencies: + inline-style-parser: 0.2.7 + + stylis@4.3.6: {} + + svgo@4.0.0: + dependencies: + commander: 11.1.0 + css-select: 5.2.2 + css-tree: 3.1.0 + css-what: 6.2.2 + csso: 5.0.5 + picocolors: 1.1.1 + sax: 1.4.3 + + tiny-inflate@1.0.3: {} + + tinyexec@1.0.2: {} + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + tlds@1.261.0: {} + + tr46@0.0.3: {} + + trim-lines@3.0.1: {} + + trough@2.2.0: {} + + ts-dedent@2.2.0: {} + + ts-pattern@5.9.0: {} + + tsconfck@3.1.6(typescript@5.9.3): + optionalDependencies: + typescript: 5.9.3 + + tslib@2.8.1: {} + + type-fest@4.41.0: {} + + typescript@5.9.3: {} + + ufo@1.6.1: {} + + uhyphen@0.2.0: {} + + uint8arrays@3.0.0: + dependencies: + multiformats: 9.9.0 + + ultrahtml@1.6.0: {} + + uncrypto@0.1.3: {} + + undici-types@5.26.5: {} + + undici-types@7.16.0: {} + + unicode-properties@1.4.1: + dependencies: + base64-js: 1.5.1 + unicode-trie: 2.0.0 + + unicode-segmenter@0.14.4: {} + + unicode-trie@2.0.0: + dependencies: + pako: 0.2.9 + tiny-inflate: 1.0.3 + + unified@11.0.5: + dependencies: + '@types/unist': 3.0.3 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.2.0 + vfile: 6.0.3 + + unifont@0.6.0: + dependencies: + css-tree: 3.1.0 + ofetch: 1.5.1 + ohash: 2.0.11 + + unist-util-find-after@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 + + unist-util-modify-children@4.0.0: + dependencies: + '@types/unist': 3.0.3 + array-iterate: 2.0.1 + + unist-util-position-from-estree@2.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-remove-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-visit: 5.0.0 + + unist-util-select@4.0.3: + dependencies: + '@types/unist': 2.0.11 + css-selector-parser: 1.4.1 + nth-check: 2.1.1 + zwitch: 2.0.4 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-children@3.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + unstorage@1.17.3: + dependencies: + anymatch: 3.1.3 + chokidar: 4.0.3 + destr: 2.0.5 + h3: 1.15.4 + lru-cache: 10.4.3 + node-fetch-native: 1.6.7 + ofetch: 1.5.1 + ufo: 1.6.1 + + util-deprecate@1.0.2: {} + + uuid@11.1.0: {} + + vfile-location@5.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile: 6.0.3 + + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.3 + + vite@6.4.1(@types/node@25.0.3): + dependencies: + esbuild: 0.25.12 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.54.0 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 25.0.3 + fsevents: 2.3.3 + + vitefu@1.1.1(vite@6.4.1(@types/node@25.0.3)): + optionalDependencies: + vite: 6.4.1(@types/node@25.0.3) + + vscode-jsonrpc@8.2.0: {} + + vscode-languageserver-protocol@3.17.5: + dependencies: + vscode-jsonrpc: 8.2.0 + vscode-languageserver-types: 3.17.5 + + vscode-languageserver-textdocument@1.0.12: {} + + vscode-languageserver-types@3.17.5: {} + + vscode-languageserver@9.0.1: + dependencies: + vscode-languageserver-protocol: 3.17.5 + + vscode-uri@3.0.8: {} + + web-namespaces@2.0.1: {} + + web-streams-polyfill@4.0.0-beta.3: {} + + webidl-conversions@3.0.1: {} + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + which-pm-runs@1.1.0: {} + + widest-line@5.0.0: + dependencies: + string-width: 7.2.0 + + wrap-ansi@9.0.2: + dependencies: + ansi-styles: 6.2.3 + string-width: 7.2.0 + strip-ansi: 7.1.2 + + xxhash-wasm@1.1.0: {} + + yargs-parser@21.1.1: {} + + yocto-queue@1.2.2: {} + + yocto-spinner@0.2.3: + dependencies: + yoctocolors: 2.1.2 + + yoctocolors@2.1.2: {} + + zod-to-json-schema@3.25.0(zod@3.25.76): + dependencies: + zod: 3.25.76 + + zod-to-ts@1.2.0(typescript@5.9.3)(zod@3.25.76): + dependencies: + typescript: 5.9.3 + zod: 3.25.76 + + zod@3.25.76: {} + + zwitch@2.0.4: {} diff --git a/docs/public/cloud/arcgis/arcgis-oauth-hybrid-initialize.mp4 b/docs/public/cloud/arcgis/arcgis-oauth-hybrid-initialize.mp4 new file mode 100644 index 00000000..6bc9995c Binary files /dev/null and b/docs/public/cloud/arcgis/arcgis-oauth-hybrid-initialize.mp4 differ diff --git a/docs/public/cloud/arcgis/arcgis-oauth-hybrid-initialize.webm b/docs/public/cloud/arcgis/arcgis-oauth-hybrid-initialize.webm new file mode 100644 index 00000000..5909dff5 Binary files /dev/null and b/docs/public/cloud/arcgis/arcgis-oauth-hybrid-initialize.webm differ diff --git a/docs/public/groundimage/interactive-ground-image.mp4 b/docs/public/groundimage/interactive-ground-image.mp4 new file mode 100644 index 00000000..597411f4 Binary files /dev/null and b/docs/public/groundimage/interactive-ground-image.mp4 differ diff --git a/docs/public/groundimage/interactive-ground-image.webm b/docs/public/groundimage/interactive-ground-image.webm new file mode 100644 index 00000000..26b1a53c Binary files /dev/null and b/docs/public/groundimage/interactive-ground-image.webm differ diff --git a/docs/public/mapcameraposition/animated-camera-example.mp4 b/docs/public/mapcameraposition/animated-camera-example.mp4 new file mode 100644 index 00000000..f64ef22a Binary files /dev/null and b/docs/public/mapcameraposition/animated-camera-example.mp4 differ diff --git a/docs/public/mapcameraposition/animated-camera-example.webm b/docs/public/mapcameraposition/animated-camera-example.webm new file mode 100644 index 00000000..63c49f40 Binary files /dev/null and b/docs/public/mapcameraposition/animated-camera-example.webm differ diff --git a/docs/public/mapcameraposition/camera-control-example.mp4 b/docs/public/mapcameraposition/camera-control-example.mp4 new file mode 100644 index 00000000..5ce54eef Binary files /dev/null and b/docs/public/mapcameraposition/camera-control-example.mp4 differ diff --git a/docs/public/mapcameraposition/camera-control-example.webm b/docs/public/mapcameraposition/camera-control-example.webm new file mode 100644 index 00000000..ae69be44 Binary files /dev/null and b/docs/public/mapcameraposition/camera-control-example.webm differ diff --git a/docs/public/mapcameraposition/visible-region-example.mp4 b/docs/public/mapcameraposition/visible-region-example.mp4 new file mode 100644 index 00000000..47c6cda8 Binary files /dev/null and b/docs/public/mapcameraposition/visible-region-example.mp4 differ diff --git a/docs/public/mapcameraposition/visible-region-example.webm b/docs/public/mapcameraposition/visible-region-example.webm new file mode 100644 index 00000000..35e647a4 Binary files /dev/null and b/docs/public/mapcameraposition/visible-region-example.webm differ diff --git a/docs/public/mapviewholder/map-view-holder-arcgis.mp4 b/docs/public/mapviewholder/map-view-holder-arcgis.mp4 new file mode 100644 index 00000000..315a7102 Binary files /dev/null and b/docs/public/mapviewholder/map-view-holder-arcgis.mp4 differ diff --git a/docs/public/mapviewholder/map-view-holder-arcgis.webm b/docs/public/mapviewholder/map-view-holder-arcgis.webm new file mode 100644 index 00000000..659da988 Binary files /dev/null and b/docs/public/mapviewholder/map-view-holder-arcgis.webm differ diff --git a/docs/public/mapviewholder/map-view-holder-googlemaps-example.mp4 b/docs/public/mapviewholder/map-view-holder-googlemaps-example.mp4 new file mode 100644 index 00000000..80982aa0 Binary files /dev/null and b/docs/public/mapviewholder/map-view-holder-googlemaps-example.mp4 differ diff --git a/docs/public/mapviewholder/map-view-holder-googlemaps-example.webm b/docs/public/mapviewholder/map-view-holder-googlemaps-example.webm new file mode 100644 index 00000000..1127368f Binary files /dev/null and b/docs/public/mapviewholder/map-view-holder-googlemaps-example.webm differ diff --git a/docs/public/mapviewholder/map-view-holder-here-example.webm b/docs/public/mapviewholder/map-view-holder-here-example.webm new file mode 100644 index 00000000..82398fc9 Binary files /dev/null and b/docs/public/mapviewholder/map-view-holder-here-example.webm differ diff --git a/docs/public/mapviewholder/map-view-holder-mapbox-example.mp4 b/docs/public/mapviewholder/map-view-holder-mapbox-example.mp4 new file mode 100644 index 00000000..f88cb106 Binary files /dev/null and b/docs/public/mapviewholder/map-view-holder-mapbox-example.mp4 differ diff --git a/docs/public/mapviewholder/map-view-holder-mapbox-example.webm b/docs/public/mapviewholder/map-view-holder-mapbox-example.webm new file mode 100644 index 00000000..3b40d316 Binary files /dev/null and b/docs/public/mapviewholder/map-view-holder-mapbox-example.webm differ diff --git a/docs/public/marker/marker-animation.gif b/docs/public/marker/marker-animation.gif new file mode 100644 index 00000000..ac8a35a0 Binary files /dev/null and b/docs/public/marker/marker-animation.gif differ diff --git a/docs/public/polygon/geodesic-polygon.mp4 b/docs/public/polygon/geodesic-polygon.mp4 new file mode 100644 index 00000000..47d9e75c Binary files /dev/null and b/docs/public/polygon/geodesic-polygon.mp4 differ diff --git a/docs/public/polygon/geodesic-polygon.webm b/docs/public/polygon/geodesic-polygon.webm new file mode 100644 index 00000000..9c39e202 Binary files /dev/null and b/docs/public/polygon/geodesic-polygon.webm differ diff --git a/docs/public/polygon/interactive-polygon-example.mp4 b/docs/public/polygon/interactive-polygon-example.mp4 new file mode 100644 index 00000000..3d8b7486 Binary files /dev/null and b/docs/public/polygon/interactive-polygon-example.mp4 differ diff --git a/docs/public/polygon/interactive-polygon-example.webm b/docs/public/polygon/interactive-polygon-example.webm new file mode 100644 index 00000000..aaa7f9e7 Binary files /dev/null and b/docs/public/polygon/interactive-polygon-example.webm differ diff --git a/docs/public/state/marker-state/animated-marker-example.gif b/docs/public/state/marker-state/animated-marker-example.gif new file mode 100644 index 00000000..2cbc6b68 Binary files /dev/null and b/docs/public/state/marker-state/animated-marker-example.gif differ diff --git a/docs/public/state/marker-state/dynamic-marker-example.mp4 b/docs/public/state/marker-state/dynamic-marker-example.mp4 new file mode 100644 index 00000000..97d2baa1 Binary files /dev/null and b/docs/public/state/marker-state/dynamic-marker-example.mp4 differ diff --git a/docs/public/state/marker-state/dynamic-marker-example.webm b/docs/public/state/marker-state/dynamic-marker-example.webm new file mode 100644 index 00000000..38c77d56 Binary files /dev/null and b/docs/public/state/marker-state/dynamic-marker-example.webm differ diff --git a/docs/public/state/marker-state/marker-state-custom-example.mp4 b/docs/public/state/marker-state/marker-state-custom-example.mp4 new file mode 100644 index 00000000..3c72c58e Binary files /dev/null and b/docs/public/state/marker-state/marker-state-custom-example.mp4 differ diff --git a/docs/public/state/marker-state/marker-state-custom-example.webm b/docs/public/state/marker-state/marker-state-custom-example.webm new file mode 100644 index 00000000..88d052d7 Binary files /dev/null and b/docs/public/state/marker-state/marker-state-custom-example.webm differ diff --git a/docs/scripts/translate-docs.mjs b/docs/scripts/translate-docs.mjs new file mode 100644 index 00000000..5a3737bc --- /dev/null +++ b/docs/scripts/translate-docs.mjs @@ -0,0 +1,151 @@ +import { execSync } from 'node:child_process'; +import fs from 'node:fs/promises'; +import { existsSync } from 'node:fs'; +import path from 'node:path'; +import process from 'node:process'; +import OpenAI from 'openai'; + +const JA_ROOT = path.join('src', 'content', 'docs', 'ja'); +const EN_ROOT = path.join('src', 'content', 'docs'); +const ES_ROOT = path.join('src', 'content', 'docs', 'es-419'); + +function getBaseCommitFromArgs() { + const args = process.argv.slice(2); + if (args.length > 0 && !args[0].startsWith('-')) { + return args[0]; + } + const envCommit = process.env.DOCS_BASE_COMMIT; + if (envCommit) { + return envCommit; + } + console.error('Usage: npm run translate:docs -- '); + console.error('Or set DOCS_BASE_COMMIT environment variable.'); + process.exit(1); +} + +function getChangedJaFiles(baseCommit) { + const cmd = `git diff --name-only ${baseCommit} HEAD -- ${JA_ROOT.replace(/\\/g, '/')}`; + let output; + try { + output = execSync(cmd, { encoding: 'utf8' }); + } catch (error) { + console.error('Failed to execute git diff. Make sure the commit id is valid.'); + console.error(error.message); + process.exit(1); + } + + const files = output + .split('\n') + .map((line) => line.trim()) + .filter((line) => line.length > 0) + .map((filePath) => path.normalize(filePath)) + .filter((filePath) => existsSync(filePath)); + + return files; +} + +function getTargetPaths(jaFilePath) { + const relativeToJa = path.relative(JA_ROOT, jaFilePath); + const enPath = path.join(EN_ROOT, relativeToJa); + const esPath = path.join(ES_ROOT, relativeToJa); + return { enPath, esPath }; +} + +function getOpenAIClient() { + const apiKey = process.env.OPENAI_API_KEY; + if (!apiKey) { + console.error('OPENAI_API_KEY environment variable is not set.'); + process.exit(1); + } + const model = process.env.DOCS_TRANSLATION_MODEL || 'gpt-4.1-mini'; + const client = new OpenAI({ apiKey }); + return { client, model }; +} + +async function translateWithOpenAI(client, model, content, targetLanguage, filePath) { + const languageName = + targetLanguage === 'en' + ? 'English' + : targetLanguage === 'es-419' + ? 'Latin American Spanish' + : targetLanguage; + + const systemPrompt = + 'You are a professional technical translator for developer documentation. ' + + 'Translate Japanese Markdown/MDX documentation into the target language. ' + + 'Preserve all Markdown/MDX syntax, code blocks, inline code, links, and frontmatter keys. ' + + 'Translate human-readable text and frontmatter string values, but do not change file structure.'; + + const userPrompt = + `Translate the following Japanese documentation into ${languageName}.\n` + + 'Keep the overall structure and formatting exactly the same.\n\n' + + '--- BEGIN FILE ---\n' + + content + + '\n--- END FILE ---\n'; + + const response = await client.chat.completions.create({ + model, + messages: [ + { role: 'system', content: systemPrompt }, + { role: 'user', content: userPrompt }, + ], + temperature: 0.2, + }); + + const translated = response.choices[0]?.message?.content; + if (!translated) { + throw new Error(`Empty translation result for ${filePath} (${targetLanguage})`); + } + return translated.trim(); +} + +async function translateFile(jaFilePath, client, model) { + const { enPath, esPath } = getTargetPaths(jaFilePath); + + const jaContent = await fs.readFile(jaFilePath, 'utf8'); + + console.log(`Translating ${jaFilePath} -> ${enPath}`); + const enContent = await translateWithOpenAI(client, model, jaContent, 'en', jaFilePath); + await fs.mkdir(path.dirname(enPath), { recursive: true }); + await fs.writeFile(enPath, enContent, 'utf8'); + + console.log(`Translating ${jaFilePath} -> ${esPath}`); + const esContent = await translateWithOpenAI(client, model, jaContent, 'es-419', jaFilePath); + await fs.mkdir(path.dirname(esPath), { recursive: true }); + await fs.writeFile(esPath, esContent, 'utf8'); +} + +async function main() { + const baseCommit = getBaseCommitFromArgs(); + console.log(`Base commit: ${baseCommit}`); + + const changedJaFiles = getChangedJaFiles(baseCommit); + if (changedJaFiles.length === 0) { + console.log('No updated Japanese docs found under src/content/docs/ja.'); + return; + } + + console.log('Updated Japanese docs:'); + for (const file of changedJaFiles) { + console.log(` - ${file}`); + } + + const { client, model } = getOpenAIClient(); + + for (const jaFile of changedJaFiles) { + try { + await translateFile(jaFile, client, model); + } catch (error) { + console.error(`Failed to translate ${jaFile}:`); + console.error(error); + } + } + + console.log('Translation finished.'); +} + +main().catch((error) => { + console.error('Unexpected error during translation:', error); + process.exit(1); +}); + diff --git a/docs/src/assets/groundimage/basic-ground-image.png b/docs/src/assets/groundimage/basic-ground-image.png new file mode 100644 index 00000000..2d615d4b Binary files /dev/null and b/docs/src/assets/groundimage/basic-ground-image.png differ diff --git a/docs/src/assets/index/circle.png b/docs/src/assets/index/circle.png new file mode 100644 index 00000000..f9957284 Binary files /dev/null and b/docs/src/assets/index/circle.png differ diff --git a/docs/src/assets/index/code-example.jpg b/docs/src/assets/index/code-example.jpg new file mode 100644 index 00000000..16c4a9c1 Binary files /dev/null and b/docs/src/assets/index/code-example.jpg differ diff --git a/docs/src/assets/index/groundimage.png b/docs/src/assets/index/groundimage.png new file mode 100644 index 00000000..1659bf6e Binary files /dev/null and b/docs/src/assets/index/groundimage.png differ diff --git a/docs/src/assets/index/heatmap.png b/docs/src/assets/index/heatmap.png new file mode 100644 index 00000000..65a85ca3 Binary files /dev/null and b/docs/src/assets/index/heatmap.png differ diff --git a/docs/src/assets/index/high-performance.png b/docs/src/assets/index/high-performance.png new file mode 100644 index 00000000..1e3e36d5 Binary files /dev/null and b/docs/src/assets/index/high-performance.png differ diff --git a/docs/src/assets/index/info-bubble.png b/docs/src/assets/index/info-bubble.png new file mode 100644 index 00000000..24605523 Binary files /dev/null and b/docs/src/assets/index/info-bubble.png differ diff --git a/docs/src/assets/index/map-conductor.png b/docs/src/assets/index/map-conductor.png new file mode 100644 index 00000000..07607753 Binary files /dev/null and b/docs/src/assets/index/map-conductor.png differ diff --git a/docs/src/assets/index/mapview.png b/docs/src/assets/index/mapview.png new file mode 100644 index 00000000..c62f8e18 Binary files /dev/null and b/docs/src/assets/index/mapview.png differ diff --git a/docs/src/assets/index/marker-cluster.png b/docs/src/assets/index/marker-cluster.png new file mode 100644 index 00000000..8558a0f4 Binary files /dev/null and b/docs/src/assets/index/marker-cluster.png differ diff --git a/docs/src/assets/index/marker.png b/docs/src/assets/index/marker.png new file mode 100644 index 00000000..7f2eb4c3 Binary files /dev/null and b/docs/src/assets/index/marker.png differ diff --git a/docs/src/assets/index/polygon.png b/docs/src/assets/index/polygon.png new file mode 100644 index 00000000..e9f30f95 Binary files /dev/null and b/docs/src/assets/index/polygon.png differ diff --git a/docs/src/assets/index/polyline.png b/docs/src/assets/index/polyline.png new file mode 100644 index 00000000..c18d6db6 Binary files /dev/null and b/docs/src/assets/index/polyline.png differ diff --git a/docs/src/assets/index/raster-layer.gif b/docs/src/assets/index/raster-layer.gif new file mode 100644 index 00000000..d9782239 Binary files /dev/null and b/docs/src/assets/index/raster-layer.gif differ diff --git a/docs/src/assets/mapviewcomponent/architecture.png b/docs/src/assets/mapviewcomponent/architecture.png new file mode 100644 index 00000000..38ee348c Binary files /dev/null and b/docs/src/assets/mapviewcomponent/architecture.png differ diff --git a/docs/src/assets/polygon/basic-polygon-example.png b/docs/src/assets/polygon/basic-polygon-example.png new file mode 100644 index 00000000..978b1d76 Binary files /dev/null and b/docs/src/assets/polygon/basic-polygon-example.png differ diff --git a/docs/src/assets/state/marker-state/marker-state-basic-example.jpg b/docs/src/assets/state/marker-state/marker-state-basic-example.jpg new file mode 100644 index 00000000..4a489e6e Binary files /dev/null and b/docs/src/assets/state/marker-state/marker-state-basic-example.jpg differ diff --git a/docs/src/astro/postBuildIntegration.ts b/docs/src/astro/postBuildIntegration.ts new file mode 100644 index 00000000..fe8ad87a --- /dev/null +++ b/docs/src/astro/postBuildIntegration.ts @@ -0,0 +1,26 @@ +import type { AstroIntegration } from 'astro'; +import { fileURLToPath } from 'node:url'; +import { processBuiltHTML } from '../utils/postBuildProcessor.ts'; + +/** + * Astro Integration: ビルド完了後のHTMLポスト処理 + * バージョンプレースホルダーをすべてのHTMLファイルで置換 + */ +export default function postBuildIntegration(): AstroIntegration { + return { + name: 'post-build-processor', + hooks: { + 'astro:build:done': async ({ dir }) => { + console.log('\n🔄 Post-processing HTML files for version placeholders...'); + try { + const distPath = fileURLToPath(dir); + await processBuiltHTML(distPath); + console.log('✅ Version placeholder processing complete!\n'); + } catch (error) { + console.error('❌ Error during post-build processing:', error); + throw error; + } + }, + }, + }; +} diff --git a/docs/src/components/api/event-handlers/CircleEventDataClass.astro b/docs/src/components/api/event-handlers/CircleEventDataClass.astro new file mode 100644 index 00000000..e483a678 --- /dev/null +++ b/docs/src/components/api/event-handlers/CircleEventDataClass.astro @@ -0,0 +1,10 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `data class CircleEvent( + val state: CircleState, + val clicked: GeoPointInterface +)`; +--- + + diff --git a/docs/src/components/api/event-handlers/MapViewEventHandlersSignature.astro b/docs/src/components/api/event-handlers/MapViewEventHandlersSignature.astro new file mode 100644 index 00000000..ce2b943c --- /dev/null +++ b/docs/src/components/api/event-handlers/MapViewEventHandlersSignature.astro @@ -0,0 +1,14 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `MapView( + ..., + onMapLoaded: OnMapLoadedHandler? = null, + onMapClick: OnMapEventHandler? = null, + onCameraMoveStart: OnCameraMoveHandler? = null, + onCameraMove: OnCameraMoveHandler? = null, + onCameraMoveEnd: OnCameraMoveHandler? = null, +) { }`; +--- + + diff --git a/docs/src/components/api/event-handlers/OnCircleClickExample.astro b/docs/src/components/api/event-handlers/OnCircleClickExample.astro new file mode 100644 index 00000000..05a1f857 --- /dev/null +++ b/docs/src/components/api/event-handlers/OnCircleClickExample.astro @@ -0,0 +1,24 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForPrint?: string; +} + +const { + commentForPrint = "A circle clicked at:" +} = Astro.props; + +const code = `Circle( + ..., + onClick = { event -> + println("${commentForPrint} \${event.clicked.latitude}, \${event.clicked.longitude}") + + event.state.fillColor = Color.Red.copy( + opacity = 0.7f, + ) + }, +)`; +--- + + diff --git a/docs/src/components/api/event-handlers/OnCircleClickSignature.astro b/docs/src/components/api/event-handlers/OnCircleClickSignature.astro new file mode 100644 index 00000000..6b020c6a --- /dev/null +++ b/docs/src/components/api/event-handlers/OnCircleClickSignature.astro @@ -0,0 +1,10 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `CircleState( + ..., + onClick: OnCircleEventHandler? = null, +)`; +--- + + diff --git a/docs/src/components/api/event-handlers/OnMapClickExample.astro b/docs/src/components/api/event-handlers/OnMapClickExample.astro new file mode 100644 index 00000000..fb9803ec --- /dev/null +++ b/docs/src/components/api/event-handlers/OnMapClickExample.astro @@ -0,0 +1,22 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForPrint?: string; +} + +const { + commentForPrint = "Map clicked at:" +} = Astro.props; + +const code = `MapView( + ... + onMapClick = { geoPoint -> + println("${commentForPrint} \${geoPoint.latitude}, \${geoPoint.longitude}") + } +) { + ... +}`; +--- + + diff --git a/docs/src/components/api/event-handlers/OnMapClickSignature.astro b/docs/src/components/api/event-handlers/OnMapClickSignature.astro new file mode 100644 index 00000000..76534c42 --- /dev/null +++ b/docs/src/components/api/event-handlers/OnMapClickSignature.astro @@ -0,0 +1,7 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `onMapClick: OnMapEventHandler? = null`; +--- + + diff --git a/docs/src/components/api/event-handlers/OnMapLoadedExample.astro b/docs/src/components/api/event-handlers/OnMapLoadedExample.astro new file mode 100644 index 00000000..eb47bfe5 --- /dev/null +++ b/docs/src/components/api/event-handlers/OnMapLoadedExample.astro @@ -0,0 +1,22 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForPrint?: string; +} + +const { + commentForPrint = "Map loaded" +} = Astro.props; + +const code = `MapView( + ... + onMapLoaded: { + println("${commentForPrint}") + }, +) { + ... +}`; +--- + + diff --git a/docs/src/components/api/event-handlers/OnMapLoadedSignature.astro b/docs/src/components/api/event-handlers/OnMapLoadedSignature.astro new file mode 100644 index 00000000..9f76eba1 --- /dev/null +++ b/docs/src/components/api/event-handlers/OnMapLoadedSignature.astro @@ -0,0 +1,7 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `onMapLoaded: OnMapLoadedHandler? = null`; +--- + + diff --git a/docs/src/components/api/event-handlers/OnMarkerAnimateSignatures.astro b/docs/src/components/api/event-handlers/OnMarkerAnimateSignatures.astro new file mode 100644 index 00000000..fd5d76d8 --- /dev/null +++ b/docs/src/components/api/event-handlers/OnMarkerAnimateSignatures.astro @@ -0,0 +1,11 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `MarkerState( + ..., + onAnimateStart: OnMarkerEventHandler? = null, + onAnimateEnd: OnMarkerEventHandler? = null, +)`; +--- + + diff --git a/docs/src/components/api/event-handlers/OnMarkerClickExample.astro b/docs/src/components/api/event-handlers/OnMarkerClickExample.astro new file mode 100644 index 00000000..b11ae4d9 --- /dev/null +++ b/docs/src/components/api/event-handlers/OnMarkerClickExample.astro @@ -0,0 +1,22 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForPrint?: string; +} + +const { + commentForPrint = "Marker clicked at:" +} = Astro.props; + +const code = `val markerState = MarkerState( + ..., + onClick = { marker -> + println("${commentForPrint} \${marker.position.latitude}, \${marker.position.longitude}") + }, +) + +Marker(markerState)`; +--- + + diff --git a/docs/src/components/api/event-handlers/OnMarkerClickSignature.astro b/docs/src/components/api/event-handlers/OnMarkerClickSignature.astro new file mode 100644 index 00000000..76aa2132 --- /dev/null +++ b/docs/src/components/api/event-handlers/OnMarkerClickSignature.astro @@ -0,0 +1,10 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `MarkerState( + ..., + onClick: OnMarkerEventHandler? = null, +)`; +--- + + diff --git a/docs/src/components/api/event-handlers/OnMarkerDragExample.astro b/docs/src/components/api/event-handlers/OnMarkerDragExample.astro new file mode 100644 index 00000000..47935f99 --- /dev/null +++ b/docs/src/components/api/event-handlers/OnMarkerDragExample.astro @@ -0,0 +1,33 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForDragStart?: string; + commentForDragEnd?: string; +} + +const { + commentForDragStart = "Drag started:", + commentForDragEnd = "Drag ended:" +} = Astro.props; + +const code = `var markerState = MarkerState( + ..., + draggable = true, + onDragStart = { draggedMarker -> + println("${commentForDragStart} \${draggedMarker.id}") + }, + onDrag = { draggedMarker -> + if (draggedMarker.id == markerState.id) { + markerState = markerState.copy(position = draggedMarker.position) + } + }, + onDragEnd = { draggedMarker -> + println("${commentForDragEnd} \${draggedMarker.id}") + }, +) + +Marker(markerState)`; +--- + + diff --git a/docs/src/components/api/event-handlers/OnMarkerDragSignatures.astro b/docs/src/components/api/event-handlers/OnMarkerDragSignatures.astro new file mode 100644 index 00000000..e593c010 --- /dev/null +++ b/docs/src/components/api/event-handlers/OnMarkerDragSignatures.astro @@ -0,0 +1,12 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `MarkerState( + ..., + onDragStart: OnMarkerEventHandler? = null, + onDrag: OnMarkerEventHandler? = null, + onDragEnd: OnMarkerEventHandler? = null, +)`; +--- + + diff --git a/docs/src/components/api/event-handlers/OnPolylineClickExample.astro b/docs/src/components/api/event-handlers/OnPolylineClickExample.astro new file mode 100644 index 00000000..5bcfdc6a --- /dev/null +++ b/docs/src/components/api/event-handlers/OnPolylineClickExample.astro @@ -0,0 +1,22 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForPrint?: string; +} + +const { + commentForPrint = "A polyline clicked at:" +} = Astro.props; + +const code = `Polyline( + ..., + onClick = { event -> + println("${commentForPrint} \${event.clicked.latitude}, \${event.clicked.longitude}") + + event.state.strokeColor = Color.Red + }, +)`; +--- + + diff --git a/docs/src/components/api/event-handlers/OnPolylineClickSignature.astro b/docs/src/components/api/event-handlers/OnPolylineClickSignature.astro new file mode 100644 index 00000000..6c964642 --- /dev/null +++ b/docs/src/components/api/event-handlers/OnPolylineClickSignature.astro @@ -0,0 +1,10 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `PolylineState( + ..., + onClick: OnPolylineEventHandler? = null, +)`; +--- + + diff --git a/docs/src/components/api/event-handlers/PolylineEventDataClass.astro b/docs/src/components/api/event-handlers/PolylineEventDataClass.astro new file mode 100644 index 00000000..d33ee52e --- /dev/null +++ b/docs/src/components/api/event-handlers/PolylineEventDataClass.astro @@ -0,0 +1,10 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `data class PolylineEvent( + val state: PolylineState, + val clicked: GeoPointInterface +)`; +--- + + diff --git a/docs/src/components/api/initialization/ArcGISExample.astro b/docs/src/components/api/initialization/ArcGISExample.astro new file mode 100644 index 00000000..0439cd11 --- /dev/null +++ b/docs/src/components/api/initialization/ArcGISExample.astro @@ -0,0 +1,36 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + functionName?: string; + rememberStateFunction?: string; + mapViewType?: string; + commentForUsage?: string; + commentForMapContent?: string; +} + +const { + functionName = "ArcGISExample", + rememberStateFunction = "rememberArcGISMapViewState", + mapViewType = "ArcGISMapView", + commentForUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView", + commentForMapContent = "Map content" +} = Astro.props; + +const usageCommentLine = + commentForUsage && commentForUsage.trim().length > 0 + ? `\n // ${commentForUsage}` + : ""; + +const code = `@Composable +fun ${functionName}() { + val mapViewState = ${rememberStateFunction}()${usageCommentLine} + + ${mapViewType}(state = mapViewState) { + // ${commentForMapContent} + } +}`; +--- + + + diff --git a/docs/src/components/api/initialization/CustomMapConfiguration.astro b/docs/src/components/api/initialization/CustomMapConfiguration.astro new file mode 100644 index 00000000..4cd7bbc2 --- /dev/null +++ b/docs/src/components/api/initialization/CustomMapConfiguration.astro @@ -0,0 +1,76 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + functionName?: string; + mapViewStateImplType?: string; + mapViewType?: string; + latitude?: number; + longitude?: number; + zoom?: number; + bearing?: number; + tilt?: number; + mapDesignType?: string; + commentForCameraPosition?: string; + commentForMapDesign?: string; + commentForUsage?: string; + commentForMapContent?: string; +} + +const { + functionName = "CustomMapConfiguration", + mapViewStateImplType = "GoogleMapViewState", + mapViewType = "GoogleMapView", + latitude = 37.7749, + longitude = -122.4194, + zoom = 12, + bearing = 45, + tilt = 30, + mapDesignType = "GoogleMapDesignType.SATELLITE", + commentForCameraPosition = "Set initial camera position", + commentForMapDesign = "Set map design/style", + commentForUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView", + commentForMapContent = "Map content" +} = Astro.props; + +const cameraCommentLine = + commentForCameraPosition && commentForCameraPosition.trim().length > 0 + ? ` // ${commentForCameraPosition}\n` + : ""; + +const mapDesignCommentLine = + commentForMapDesign && commentForMapDesign.trim().length > 0 + ? `\n // ${commentForMapDesign}\n` + : "\n"; + +const usageCommentLine = + commentForUsage && commentForUsage.trim().length > 0 + ? ` // ${commentForUsage}\n` + : ""; + +const code = `@Composable +fun ${functionName}() { + val mapViewState = remember { + ${mapViewStateImplType}().apply { +${cameraCommentLine} initCameraPosition = MapCameraPosition( + target = GeoPoint.fromLatLong(${latitude}, ${longitude}), + zoom = ${zoom}f, + bearing = ${bearing}f, + tilt = ${tilt}f + )${mapDesignCommentLine} mapDesignType = ${mapDesignType} + } + } + +${usageCommentLine} ${mapViewType}( + state = mapViewState, + onMapLoaded = { + println("Map loaded and ready") + } + ) { + // ${commentForMapContent} + } +}`; +--- + + + diff --git a/docs/src/components/api/initialization/GoogleMapsExample.astro b/docs/src/components/api/initialization/GoogleMapsExample.astro new file mode 100644 index 00000000..e3fd858e --- /dev/null +++ b/docs/src/components/api/initialization/GoogleMapsExample.astro @@ -0,0 +1,36 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + functionName?: string; + rememberStateFunction?: string; + mapViewType?: string; + commentForUsage?: string; + commentForMapContent?: string; +} + +const { + functionName = "GoogleMapsExample", + rememberStateFunction = "rememberGoogleMapViewState", + mapViewType = "GoogleMapView", + commentForUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView", + commentForMapContent = "Map content" +} = Astro.props; + +const usageCommentLine = + commentForUsage && commentForUsage.trim().length > 0 + ? `\n // ${commentForUsage}` + : ""; + +const code = `@Composable +fun ${functionName}() { + val mapViewState = ${rememberStateFunction}()${usageCommentLine} + + ${mapViewType}(state = mapViewState) { + // ${commentForMapContent} + } +}`; +--- + + + diff --git a/docs/src/components/api/initialization/GradleDependencies.astro b/docs/src/components/api/initialization/GradleDependencies.astro new file mode 100644 index 00000000..11b642ac --- /dev/null +++ b/docs/src/components/api/initialization/GradleDependencies.astro @@ -0,0 +1,28 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForChooseProvider?: string; + bomVersionPlaceholder?: string; +} + +const { + commentForChooseProvider = "Choose your map provider(s)", + bomVersionPlaceholder = "$version", +} = Astro.props; + +const code = `dependencies { + implementation "com.mapconductor:mapconductor-bom:${bomVersionPlaceholder}" + implementation "com.mapconductor:core" + + // ${commentForChooseProvider} + implementation "com.mapconductor:for-googlemaps" + implementation "com.mapconductor:for-mapbox" + implementation "com.mapconductor:for-here" + implementation "com.mapconductor:for-arcgis" + implementation "com.mapconductor:for-maplibre" +}`; +--- + + + diff --git a/docs/src/components/api/initialization/HereExample.astro b/docs/src/components/api/initialization/HereExample.astro new file mode 100644 index 00000000..cb8bc4e2 --- /dev/null +++ b/docs/src/components/api/initialization/HereExample.astro @@ -0,0 +1,36 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + functionName?: string; + rememberStateFunction?: string; + mapViewType?: string; + commentForUsage?: string; + commentForMapContent?: string; +} + +const { + functionName = "HereExample", + rememberStateFunction = "rememberHereMapViewState", + mapViewType = "HereMapView", + commentForUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView", + commentForMapContent = "Map content" +} = Astro.props; + +const usageCommentLine = + commentForUsage && commentForUsage.trim().length > 0 + ? `\n // ${commentForUsage}` + : ""; + +const code = `@Composable +fun ${functionName}() { + val mapViewState = ${rememberStateFunction}()${usageCommentLine} + + ${mapViewType}(state = mapViewState) { + // ${commentForMapContent} + } +}`; +--- + + + diff --git a/docs/src/components/api/initialization/MapLibreExample.astro b/docs/src/components/api/initialization/MapLibreExample.astro new file mode 100644 index 00000000..46061ae4 --- /dev/null +++ b/docs/src/components/api/initialization/MapLibreExample.astro @@ -0,0 +1,36 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + functionName?: string; + rememberStateFunction?: string; + mapViewType?: string; + commentForUsage?: string; + commentForMapContent?: string; +} + +const { + functionName = "GoogleMapsExample", + rememberStateFunction = "rememberMapLibreViewState", + mapViewType = "MapLibreView", + commentForUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView", + commentForMapContent = "Map content" +} = Astro.props; + +const usageCommentLine = + commentForUsage && commentForUsage.trim().length > 0 + ? `\n // ${commentForUsage}` + : ""; + +const code = `@Composable +fun ${functionName}() { + val mapViewState = ${rememberStateFunction}()${usageCommentLine} + + ${mapViewType}(state = mapViewState) { + // ${commentForMapContent} + } +}`; +--- + + + diff --git a/docs/src/components/api/initialization/MapboxExample.astro b/docs/src/components/api/initialization/MapboxExample.astro new file mode 100644 index 00000000..4e7b2b69 --- /dev/null +++ b/docs/src/components/api/initialization/MapboxExample.astro @@ -0,0 +1,36 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + functionName?: string; + rememberStateFunction?: string; + mapViewType?: string; + commentForUsage?: string; + commentForMapContent?: string; +} + +const { + functionName = "MapboxExample", + rememberStateFunction = "rememberMapboxMapViewState", + mapViewType = "MapboxMapView", + commentForUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView", + commentForMapContent = "Map content" +} = Astro.props; + +const usageCommentLine = + commentForUsage && commentForUsage.trim().length > 0 + ? `\n // ${commentForUsage}` + : ""; + +const code = `@Composable +fun ${functionName}() { + val mapViewState = ${rememberStateFunction}()${usageCommentLine} + + ${mapViewType}(state = mapViewState) { + // ${commentForMapContent} + } +}`; +--- + + + diff --git a/docs/src/components/cloud/arcgis/ArcGISOAuthHybridInitialize.astro b/docs/src/components/cloud/arcgis/ArcGISOAuthHybridInitialize.astro new file mode 100644 index 00000000..d5af2441 --- /dev/null +++ b/docs/src/components/cloud/arcgis/ArcGISOAuthHybridInitialize.astro @@ -0,0 +1,14 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `suspend fun ArcGISOAuthHybridInitialize( + authenticatorState: AuthenticatorState, + portalUrl: String, + redirectUrl: String, + clientId: String, + clientSecret: String? = null, +): Boolean`; +--- + + + diff --git a/docs/src/components/cloud/arcgis/ArcGISOAuthHybridInitializeExample.astro b/docs/src/components/cloud/arcgis/ArcGISOAuthHybridInitializeExample.astro new file mode 100644 index 00000000..0cd8b21e --- /dev/null +++ b/docs/src/components/cloud/arcgis/ArcGISOAuthHybridInitializeExample.astro @@ -0,0 +1,90 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentCameraPosition?: string; + commentAuthStateAndScope?: string; + commentAwaitStyleExecution?: string; + commentWaitForSceneLoad?: string; + commentSceneViewWebSceneOnly?: string; + commentAdditionalLayerExample?: string; + commentAuthenticatorUI?: string; +} + +const { + commentCameraPosition = '地図のカメラ位置', + commentAuthStateAndScope = '認証状態と CoroutineScope(await ライクに逐次処理)', + commentAwaitStyleExecution = 'await 風に直列実行', + commentWaitForSceneLoad = 'WebSceneの読み込み完了を待つ', + commentSceneViewWebSceneOnly = 'SceneView は WebScene のみ対応', + commentAdditionalLayerExample = '追加レイヤ例(任意)', + commentAuthenticatorUI = '認証UI(ユーザーログイン用)。ハイブリッド認証のフォールバックで使用されます。', +} = Astro.props; + +const code = `@Composable +fun BasicMapExample(modifier: Modifier = Modifier) { + // ${commentCameraPosition} + val mapViewState = + rememberArcGISMapViewState( + cameraPosition = + MapCameraPosition( + position = GeoPoint.fromLatLong(35.6812, 139.7671), + zoom = 12.0, + ), + ) + + // ${commentAuthStateAndScope} + val authenticatorState = remember { AuthenticatorState() } + val scope = rememberCoroutineScope() + + ArcGISMapView( + state = mapViewState, + modifier = modifier.fillMaxSize(), + sdkInitialize = { context -> + ArcGISOAuthHybridInitialize( + authenticatorState = authenticatorState, + portalUrl = "(ArcGIS Portal URL)", + redirectUrl = "(Redirect URL)", + clientId = (APP CLIENT ID), + clientSecret = "(APP CLIENT SECRET)", + ) + }, + onMapLoaded = { + scope.launch { + val holder = mapViewState.getMapViewHolder() ?: return@launch + + // ${commentAwaitStyleExecution} + val portal = Portal("https://mkgeeklab.maps.arcgis.com/", Portal.Connection.Authenticated) + portal.load().getOrThrow() + + val item = PortalItem(portal, "e0ce06974e3d4c79b37e30d224c585d3") + item.load().getOrThrow() + + when (item.type) { + is PortalItemType.WebScene -> { + ArcGISScene(item).also { + it.load().getOrThrow() // ${commentWaitForSceneLoad} + holder.map.scene = it + } + } + is PortalItemType.WebMap -> error("${commentSceneViewWebSceneOnly}") + else -> error("Unknown item type: \${item.type}") + } + + // ${commentAdditionalLayerExample} + val trafficServerUrl = "https://traffic.arcgis.com/arcgis/rest/services/World/Traffic/MapServer" + ArcGISMapImageLayer(trafficServerUrl).also { + it.opacity = 0.6f + holder.map.scene!!.operationalLayers.add(0, it) + } + } + } + ) {} + + // ${commentAuthenticatorUI} + Authenticator(authenticatorState = authenticatorState, modifier = modifier) +}`; +--- + + + diff --git a/docs/src/components/components/circle/BasicCircleExample.astro b/docs/src/components/components/circle/BasicCircleExample.astro new file mode 100644 index 00000000..aec050e7 --- /dev/null +++ b/docs/src/components/components/circle/BasicCircleExample.astro @@ -0,0 +1,25 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `// ${commentForMapViewUsage} +MapView(state = mapViewState) { + Circle( + center = GeoPoint.fromLatLong(37.7749, -122.4194), + radiusMeters = 1000.0, // 1km radius + strokeColor = Color.Blue, + fillColor = Color.Blue.copy(alpha = 0.3f), + id = "downtown-area" + ) +}`; +--- + + + diff --git a/docs/src/components/components/circle/CircleBasicSignature.astro b/docs/src/components/components/circle/CircleBasicSignature.astro new file mode 100644 index 00000000..79026ec4 --- /dev/null +++ b/docs/src/components/components/circle/CircleBasicSignature.astro @@ -0,0 +1,18 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `@Composable +fun MapViewScope.Circle( + center: GeoPointInterface, + radiusMeters: Double, + geodesic: Boolean = false, + strokeColor: Color = Color.Red, + strokeWidth: Dp = 2.dp, + fillColor: Color = Color.White.copy(alpha = 0.5f), + extra: Serializable? = null, + id: String? = null +)`; +--- + + + diff --git a/docs/src/components/components/circle/CircleClickEventDetailedExample.astro b/docs/src/components/components/circle/CircleClickEventDetailedExample.astro new file mode 100644 index 00000000..4c97ce13 --- /dev/null +++ b/docs/src/components/components/circle/CircleClickEventDetailedExample.astro @@ -0,0 +1,32 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `@Composable +fun CircleClickEventExample() { + val mapViewState = rememberGoogleMapViewState() + + // Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView + MapView( + state = mapViewState + ) { + Circle( + center = GeoPoint.fromLatLong(37.7749, -122.4194), + radiusMeters = 1000.0, + clickable = true, + extra = "Clickable circle", + onClick = { circleEvent -> + val circle = circleEvent.state + val clickPoint = circleEvent.clicked + + println("Circle clicked:") + println(" Center: \${circle.center}") + println(" Radius: \${circle.radiusMeters}m") + println(" Click point: \${clickPoint}") + println(" Extra data: \${circle.extra}") + } + ) + } +}`; +--- + + diff --git a/docs/src/components/components/circle/CircleEventHandlingExample.astro b/docs/src/components/components/circle/CircleEventHandlingExample.astro new file mode 100644 index 00000000..ff614e03 --- /dev/null +++ b/docs/src/components/components/circle/CircleEventHandlingExample.astro @@ -0,0 +1,35 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `// ${commentForMapViewUsage} +MapView( + state = mapViewState +) { + Circle( + center = GeoPoint.fromLatLong(37.7749, -122.4194), + radiusMeters = 1000.0, + clickable = true, + extra = "Clickable circle", + onClick = { circleEvent -> + val circle = circleEvent.state + val clickPoint = circleEvent.clicked + + println("Circle clicked:") + println(" Center: ${'${'}circle.center}") + println(" Radius: ${'${'}circle.radiusMeters}m") + println(" Click point: ${'${'}clickPoint}") + println(" Extra data: ${'${'}circle.extra}") + } + ) +}`; +--- + + diff --git a/docs/src/components/components/circle/CircleFillStylesExample.astro b/docs/src/components/components/circle/CircleFillStylesExample.astro new file mode 100644 index 00000000..7782bafd --- /dev/null +++ b/docs/src/components/components/circle/CircleFillStylesExample.astro @@ -0,0 +1,27 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `// Solid fill +Circle( + center = center, + radiusMeters = 500.0, + fillColor = Color.Red +) + +// Semi-transparent fill +Circle( + center = center, + radiusMeters = 500.0, + fillColor = Color.Red.copy(alpha = 0.5f) +) + +// No fill +Circle( + center = center, + radiusMeters = 500.0, + fillColor = Color.Transparent +)`; +--- + + + diff --git a/docs/src/components/components/circle/CircleIdDetailedExample.astro b/docs/src/components/components/circle/CircleIdDetailedExample.astro new file mode 100644 index 00000000..36442597 --- /dev/null +++ b/docs/src/components/components/circle/CircleIdDetailedExample.astro @@ -0,0 +1,57 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `@Composable +fun CircleIdentificationExample() { + val mapViewState = rememberGoogleMapViewState() + + // Use ID in event handling + val onCircleClick: OnCircleEventHandler = { circleEvent -> + when (circleEvent.state.id) { + "zone-a" -> handleZoneA() + "zone-b" -> handleZoneB() + else -> handleUnknownZone() + } + } + + // Create circles with unique IDs + val circles = listOf( + CircleState( + center = GeoPoint.fromLatLong(37.7749, -122.4194), + radiusMeters = 1000.0, + strokeColor = Color.Red, + fillColor = Color.Red.copy(alpha = 0.3f), + id = "zone-a", + onClick = onCircleClick + ), + CircleState( + center = GeoPoint.fromLatLong(37.7849, -122.4094), + radiusMeters = 1500.0, + strokeColor = Color.Blue, + fillColor = Color.Blue.copy(alpha = 0.3f), + id = "zone-b", + onClick = onCircleClick + ) + ) + + MapView( + state = mapViewState + ) { + circles.forEach { circle -> Circle(circle) } + } +} + +private fun handleZoneA() { + println("Zone A clicked") +} + +private fun handleZoneB() { + println("Zone B clicked") +} + +private fun handleUnknownZone() { + println("Unknown zone clicked") +}`; +--- + + diff --git a/docs/src/components/components/circle/CircleInteractiveDetailedExample.astro b/docs/src/components/components/circle/CircleInteractiveDetailedExample.astro new file mode 100644 index 00000000..a570c810 --- /dev/null +++ b/docs/src/components/components/circle/CircleInteractiveDetailedExample.astro @@ -0,0 +1,76 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `@Composable +fun InteractiveCircleExample() { + val circleCenter = GeoPoint.fromLatLong(21.382314, -157.933097) + + // calculatePositionAtDistance is a MapConductor utility function + // Calculates position 1000m away from circleCenter, rotated 180 degrees clockwise + val edgeMarkerPosition = calculatePositionAtDistance( + center = circleCenter, + distanceMeters = 1000.0, + bearingDegrees = 180.0, + ) + + // Marker placed at the edge of the circle + val edgeMarkerState = MarkerState( + id = "edge_marker", + position = edgeMarkerPosition, + icon = DefaultIcon( + fillColor = Color.Green, + strokeColor = Color.White, + label = "Drag me", + ), + draggable = true, + onDragStart = onMarkerMove, + onDrag = onMarkerMove, + onDragEnd = onMarkerMove, + ) + + // Create CircleState + val circleState = remember { + CircleState( + id = "circle", + center = circleCenter, + radiusMeters = 1000.0, + ) + } + + // Update circle radius when marker moves + // Without specifying circleState.id, a new circle would be created on recomposition + val onMarkerMove: OnMarkerEventHandler = { markerState -> + circleState.radiusMeters = computeDistanceBetween(circleCenter, markerState.position) + } + LaunchedEffect(Unit) { + onMarkerMove(edgeMarkerState) + } + + // Create map + val camera = MapCameraPosition( + position = circleCenter, + zoom = 13.0, + ) + val mapViewState = rememberMapLibreMapViewState( + cameraPosition = camera, + ) + + MapLibreMapView( + modifier = modifier, + state = mapViewState + ) { + // Circle + Circle(circleState) + + // Center marker (not draggable) + Marker( + position = circleCenter, + ) + + // Edge marker (draggable) + Marker(edgeMarkerState) + } +}`; +--- + + diff --git a/docs/src/components/components/circle/CircleStateSignature.astro b/docs/src/components/components/circle/CircleStateSignature.astro new file mode 100644 index 00000000..629615be --- /dev/null +++ b/docs/src/components/components/circle/CircleStateSignature.astro @@ -0,0 +1,20 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `CircleState( + center: GeoPointInterface, + radiusMeters: Double, + geodesic: Boolean = false, + strokeColor: Color = Color.Red, + strokeWidth: Dp = 2.dp, + fillColor: Color = Color.White.copy(alpha = 0.5f), + extra: Serializable? = null, + id: String? = null +) + +@Composable +fun MapViewScope.Circle(state: CircleState)`; +--- + + + diff --git a/docs/src/components/components/circle/CircleStrokeStylesExample.astro b/docs/src/components/components/circle/CircleStrokeStylesExample.astro new file mode 100644 index 00000000..ffe03780 --- /dev/null +++ b/docs/src/components/components/circle/CircleStrokeStylesExample.astro @@ -0,0 +1,30 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `// Thin border +Circle( + center = center, + radiusMeters = 500.0, + strokeColor = Color.Black, + strokeWidth = 1.dp +) + +// Thick border +Circle( + center = center, + radiusMeters = 500.0, + strokeColor = Color.Black, + strokeWidth = 5.dp +) + +// No border +Circle( + center = center, + radiusMeters = 500.0, + strokeColor = Color.Transparent, + strokeWidth = 0.dp +)`; +--- + + + diff --git a/docs/src/components/components/circle/DynamicCircleExample.astro b/docs/src/components/components/circle/DynamicCircleExample.astro new file mode 100644 index 00000000..fe1f73ff --- /dev/null +++ b/docs/src/components/components/circle/DynamicCircleExample.astro @@ -0,0 +1,62 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `@Composable +fun DynamicCircleExample() { + var circleRadius by remember { mutableStateOf(500.0) } + var circleColor by remember { mutableStateOf(Color.Blue) } + + Column { + // Controls + Slider( + value = circleRadius.toFloat(), + onValueChange = { circleRadius = it.toDouble() }, + valueRange = 100f..2000f, + modifier = Modifier.padding(16.dp) + ) + + Row { + Button(onClick = { circleColor = Color.Red }) { + Text("Red") + } + Button(onClick = { circleColor = Color.Blue }) { + Text("Blue") + } + Button(onClick = { circleColor = Color.Green }) { + Text("Green") + } + } + + // Map with dynamic circle + // ${commentForMapViewUsage} + MapView(state = mapViewState) { + Circle( + center = GeoPoint.fromLatLong(37.7749, -122.4194), + radiusMeters = circleRadius, + strokeColor = circleColor, + fillColor = circleColor.copy(alpha = 0.3f) + ) + + // Center marker + Marker( + position = GeoPoint.fromLatLong(37.7749, -122.4194), + icon = DefaultIcon( + fillColor = circleColor, + label = "${'${'}circleRadius.toInt()}m" + ) + ) + } + } +}`; +--- + + + diff --git a/docs/src/components/components/circle/InteractiveCircleExample.astro b/docs/src/components/components/circle/InteractiveCircleExample.astro new file mode 100644 index 00000000..93b39123 --- /dev/null +++ b/docs/src/components/components/circle/InteractiveCircleExample.astro @@ -0,0 +1,77 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; + commentForLatOffsetNote?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView", + commentForLatOffsetNote = "This is simplified - actual calculation would consider Earth's curvature" +} = Astro.props; + +const code = `@Composable +fun InteractiveCircleExample() { + var centerPosition by remember { + mutableStateOf(GeoPoint.fromLatLong(37.7749, -122.4194)) + } + var radiusMeters by remember { mutableStateOf(1000.0) } + + // Calculate edge marker position + val edgePosition = remember(centerPosition, radiusMeters) { + // Calculate a point that's 'radiusMeters' meters away from center + // ${commentForLatOffsetNote} + val latOffset = radiusMeters / 111000.0 // Rough meters per degree latitude + GeoPoint.fromLatLong( + centerPosition.latitude + latOffset, + centerPosition.longitude + ) + } + + val circleState = CircleState( + center = centerPosition, + radiusMeters = radiusMeters, + strokeColor = Color.Blue, + fillColor = Color.Blue.copy(alpha = 0.3f), + clickable = true, + onClick = { circleEvent -> + println("Circle clicked at: ${'${'}circleEvent.clicked}") + } + ) + + val centerMarker = MarkerState( + position = centerPosition, + icon = DefaultIcon( + fillColor = Color.Blue, + label = "C" + ), + draggable = false + ) + + val edgeMarker = MarkerState( + position = edgePosition, + icon = DefaultIcon( + fillColor = Color.Green, + label = "E" + ), + draggable = true, + onDrag = { markerState -> + // Calculate new radius based on edge marker position + val distance = calculateDistance(centerPosition, markerState.position) + radiusMeters = distance + } + ) + + // ${commentForMapViewUsage} + MapView( + state = mapViewState + ) { + Circle(circleState) + Marker(centerMarker) + Marker(edgeMarker) + } +}`; +--- + + diff --git a/docs/src/components/components/circle/MultipleCirclesExample.astro b/docs/src/components/components/circle/MultipleCirclesExample.astro new file mode 100644 index 00000000..244e4284 --- /dev/null +++ b/docs/src/components/components/circle/MultipleCirclesExample.astro @@ -0,0 +1,47 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `// ${commentForMapViewUsage} +MapView(state = mapViewState) { + // Solid red circle + Circle( + center = GeoPoint.fromLatLong(37.7749, -122.4194), + radiusMeters = 500.0, + strokeColor = Color.Red, + strokeWidth = 3.dp, + fillColor = Color.Red.copy(alpha = 0.2f), + extra = "Red zone" + ) + + // Blue circle with thick border + Circle( + center = GeoPoint.fromLatLong(37.7849, -122.4194), + radiusMeters = 750.0, + strokeColor = Color.Blue, + strokeWidth = 5.dp, + fillColor = Color.Transparent, + extra = "Blue boundary" + ) + + // Green circle with pattern + Circle( + center = GeoPoint.fromLatLong(37.7649, -122.4194), + radiusMeters = 300.0, + strokeColor = Color.Green, + strokeWidth = 2.dp, + fillColor = Color.Green.copy(alpha = 0.4f), + extra = "Green area" + ) +}`; +--- + + + diff --git a/docs/src/components/components/circle/OverlappingCirclesExample.astro b/docs/src/components/components/circle/OverlappingCirclesExample.astro new file mode 100644 index 00000000..17435abc --- /dev/null +++ b/docs/src/components/components/circle/OverlappingCirclesExample.astro @@ -0,0 +1,37 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `// ${commentForMapViewUsage} +MapView(state = mapViewState) { + val centerPoint = GeoPoint.fromLatLong(37.7749, -122.4194) + + // Background circle (larger, lower z-index) + Circle( + center = centerPoint, + radiusMeters = 1000.0, + strokeColor = Color.Red, + fillColor = Color.Red.copy(alpha = 0.2f), + extra = CircleData(zIndex = 1, name = "Outer circle") + ) + + // Foreground circle (smaller, higher z-index) + Circle( + center = centerPoint, + radiusMeters = 500.0, + strokeColor = Color.Blue, + fillColor = Color.Blue.copy(alpha = 0.4f), + extra = CircleData(zIndex = 2, name = "Inner circle") + ) +}`; +--- + + + diff --git a/docs/src/components/components/groundimage/BasicGroundImageExample.astro b/docs/src/components/components/groundimage/BasicGroundImageExample.astro new file mode 100644 index 00000000..036f2a80 --- /dev/null +++ b/docs/src/components/components/groundimage/BasicGroundImageExample.astro @@ -0,0 +1,38 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `@Composable +fun BasicGroundImageExample( + drawable: Drawable, + modifier: Modifier = Modifier, +) { + val mapViewState = + rememberGoogleMapViewState( + cameraPosition = + MapCameraPosition( + position = GeoPoint(51.511649,-0.100761), + zoom = 12.0, + ), + ) + + val bounds = GeoRectBounds( + southWest = GeoPoint.fromLatLng(51.476747, -0.167729), + northEast = GeoPoint.fromLatLng(51.546550,-0.033792), + ) + GoogleMapView( + modifier = modifier, + state = mapViewState, + ) { + GroundImage( + id = "groundimage", + bounds = bounds, + image = drawable, + opacity = 0.6f + ) + } +}`; +--- + + + +image: http://maps.bpl.org, CC BY 2.0, via Wikimedia Commons diff --git a/docs/src/components/components/groundimage/DynamicGroundImageExample.astro b/docs/src/components/components/groundimage/DynamicGroundImageExample.astro new file mode 100644 index 00000000..d5a3a1f1 --- /dev/null +++ b/docs/src/components/components/groundimage/DynamicGroundImageExample.astro @@ -0,0 +1,59 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `@Composable +fun DynamicGroundImageExample() { + var selectedImageResource by remember { mutableStateOf(R.drawable.overlay1) } + var isVisible by remember { mutableStateOf(true) } + + val context = LocalContext.current + val imageDrawable = AppCompatResources.getDrawable(context, selectedImageResource) + + val bounds = GeoRectBounds( + southwest = GeoPoint.fromLatLong(37.7649, -122.4294), + northeast = GeoPoint.fromLatLong(37.7849, -122.4094) + ) + + Column { + Row { + Button(onClick = { selectedImageResource = R.drawable.overlay1 }) { + Text("Image 1") + } + Button(onClick = { selectedImageResource = R.drawable.overlay2 }) { + Text("Image 2") + } + Button(onClick = { selectedImageResource = R.drawable.overlay3 }) { + Text("Image 3") + } + } + + Switch( + checked = isVisible, + onCheckedChange = { isVisible = it }, + modifier = Modifier.padding(16.dp) + ) + + MapView(state = mapViewState) { + if (isVisible && imageDrawable != null) { + GroundImage( + bounds = bounds, + image = imageDrawable, + opacity = 0.7f, + extra = "Dynamic overlay" + ) + } + + Marker( + position = bounds.southwest, + icon = DefaultIcon(fillColor = Color.Green, label = "SW", scale = 0.6f) + ) + Marker( + position = bounds.northeast, + icon = DefaultIcon(fillColor = Color.Red, label = "NE", scale = 0.6f) + ) + } + } +}`; +--- + + diff --git a/docs/src/components/components/groundimage/GroundImageBasicSignature.astro b/docs/src/components/components/groundimage/GroundImageBasicSignature.astro new file mode 100644 index 00000000..0747f201 --- /dev/null +++ b/docs/src/components/components/groundimage/GroundImageBasicSignature.astro @@ -0,0 +1,14 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `@Composable +fun MapViewScope.GroundImage( + bounds: GeoRectBounds, + image: Drawable, + opacity: Float = 0.5f, + id: String? = null, + extra: Serializable? = null +)`; +--- + + diff --git a/docs/src/components/components/groundimage/GroundImageEventHandlingExample.astro b/docs/src/components/components/groundimage/GroundImageEventHandlingExample.astro new file mode 100644 index 00000000..9e190526 --- /dev/null +++ b/docs/src/components/components/groundimage/GroundImageEventHandlingExample.astro @@ -0,0 +1,30 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `@Composable +fun GroundImageEventHandlingExample(overlayImage: Drawable) { + val mapViewState = rememberGoogleMapViewState() + + GoogleMapView( + state = mapViewState + ) { + val imageBounds = GeoRectBounds( + northWest = GeoPoint.fromLatLong(37.8, -122.5), + southEast = GeoPoint.fromLatLong(37.7, -122.4) + ) + + GroundImage( + bounds = imageBounds, + image = overlayImage, + opacity = 0.7f, + extra = "Base map overlay", + onClick = { groundImageEvent -> + println("Ground image clicked at: \${groundImageEvent.clicked}") + println("Ground image: \${groundImageEvent.state}") + } + ) + } +}`; +--- + + diff --git a/docs/src/components/components/groundimage/GroundImageOpacityStylesExample.astro b/docs/src/components/components/groundimage/GroundImageOpacityStylesExample.astro new file mode 100644 index 00000000..e4fdde06 --- /dev/null +++ b/docs/src/components/components/groundimage/GroundImageOpacityStylesExample.astro @@ -0,0 +1,34 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `@Composable +fun GroundImageOpacityStylesExample() { + val bounds = GeoRectBounds( + northWest = GeoPoint.fromLatLong(37.8, -122.5), + southEast = GeoPoint.fromLatLong(37.7, -122.4) + ) + + // Completely transparent + GroundImage( + bounds = bounds, + image = drawable, + opacity = 0.0f + ) + + // Semi-transparent + GroundImage( + bounds = bounds, + image = drawable, + opacity = 0.5f + ) + + // Opaque + GroundImage( + bounds = bounds, + image = drawable, + opacity = 1.0f + ) +}`; +--- + + diff --git a/docs/src/components/components/groundimage/GroundImageStateSignature.astro b/docs/src/components/components/groundimage/GroundImageStateSignature.astro new file mode 100644 index 00000000..c4f81482 --- /dev/null +++ b/docs/src/components/components/groundimage/GroundImageStateSignature.astro @@ -0,0 +1,8 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `@Composable +fun MapViewScope.GroundImage(state: GroundImageState)`; +--- + + diff --git a/docs/src/components/components/groundimage/InteractiveGroundImageExample.astro b/docs/src/components/components/groundimage/InteractiveGroundImageExample.astro new file mode 100644 index 00000000..8d215f37 --- /dev/null +++ b/docs/src/components/components/groundimage/InteractiveGroundImageExample.astro @@ -0,0 +1,57 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `@Composable +fun MapView( + drawable: Drawable, + modifier: Modifier = Modifier, +) { + val mapViewState = + rememberGoogleMapViewState( + cameraPosition = + MapCameraPosition( + position = GeoPoint(51.511649,-0.100761), + zoom = 12.0, + ), + ) + + var marker1 by remember { mutableStateOf(MarkerState( + position = GeoPoint.fromLatLong(51.476747,-0.167729), + draggable = true, + )) } + var marker2 by remember { mutableStateOf(MarkerState( + position = GeoPoint.fromLatLong(51.546550,-0.033792), + draggable = true, + )) } + val bounds = GeoRectBounds( + southWest = marker1.position as GeoPoint, + northEast = marker2.position as GeoPoint, + ) + var opacity by remember { mutableStateOf(0.7f) } + + Column( + modifier = modifier, + ) { + Slider( + value = opacity, + onValueChange = { opacity = it }, + valueRange = 0f..1f, + modifier = Modifier.padding(16.dp) + ) + GoogleMapView( + state = mapViewState, + ) { + Marker(marker1) + Marker(marker2) + GroundImage( + id = "groundimage", + bounds = bounds, + image = drawable, + opacity = opacity + ) + } + } +}`; +--- + + diff --git a/docs/src/components/components/groundimage/MultipleGroundImagesExample.astro b/docs/src/components/components/groundimage/MultipleGroundImagesExample.astro new file mode 100644 index 00000000..7c18d158 --- /dev/null +++ b/docs/src/components/components/groundimage/MultipleGroundImagesExample.astro @@ -0,0 +1,51 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `@Composable +fun MultipleGroundImagesExample() { + val context = LocalContext.current + + MapView(state = mapViewState) { + // ベース衛星画像(低い不透明度) + AppCompatResources.getDrawable(context, R.drawable.satellite_base)?.let { drawable -> + GroundImage( + bounds = GeoRectBounds( + southwest = GeoPoint.fromLatLong(37.7549, -122.4394), + northeast = GeoPoint.fromLatLong(37.7949, -122.3994) + ), + image = drawable, + opacity = 0.3f, + extra = "Satellite base" + ) + } + + // 気象オーバーレイ(中程度の不透明度) + AppCompatResources.getDrawable(context, R.drawable.weather_overlay)?.let { drawable -> + GroundImage( + bounds = GeoRectBounds( + southwest = GeoPoint.fromLatLong(37.7649, -122.4294), + northeast = GeoPoint.fromLatLong(37.7849, -122.4094) + ), + image = drawable, + opacity = 0.6f, + extra = "Weather data" + ) + } + + // 交通オーバーレイ(高い不透明度) + AppCompatResources.getDrawable(context, R.drawable.traffic_overlay)?.let { drawable -> + GroundImage( + bounds = GeoRectBounds( + southwest = GeoPoint.fromLatLong(37.7699, -122.4244), + northeast = GeoPoint.fromLatLong(37.7799, -122.4144) + ), + image = drawable, + opacity = 0.8f, + extra = "Traffic data" + ) + } + } +}`; +--- + + diff --git a/docs/src/components/components/infobubble/CustomPositioningExample.astro b/docs/src/components/components/infobubble/CustomPositioningExample.astro new file mode 100644 index 00000000..f87909e0 --- /dev/null +++ b/docs/src/components/components/infobubble/CustomPositioningExample.astro @@ -0,0 +1,45 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForBottomAnchorIntro?: string; + commentForBottomAnchorAnchor?: string; + commentForCenterAnchorIntro?: string; + commentForCenterAnchorAnchor?: string; + bottomAnchorX?: number; + bottomAnchorY?: number; + centerAnchorX?: number; + centerAnchorY?: number; +} + +const { + commentForBottomAnchorIntro = "Marker with bottom-center anchor - bubble will appear above", + commentForBottomAnchorAnchor = "Bottom center", + commentForCenterAnchorIntro = "Marker with center anchor - bubble will appear above center", + commentForCenterAnchorAnchor = "Center", + bottomAnchorX = 0.5, + bottomAnchorY = 1.0, + centerAnchorX = 0.5, + centerAnchorY = 0.5 +} = Astro.props; + +const code = `// ${commentForBottomAnchorIntro} +val markerWithBottomAnchor = MarkerState( + position = position, + icon = ImageDefaultIcon( + drawable = customIcon, + anchor = Offset(${bottomAnchorX}f, ${bottomAnchorY}f) // ${commentForBottomAnchorAnchor} + ) +) + +// ${commentForCenterAnchorIntro} +val markerWithCenterAnchor = MarkerState( + position = position, + icon = ImageDefaultIcon( + drawable = customIcon, + anchor = Offset(${centerAnchorX}f, ${centerAnchorY}f) // ${commentForCenterAnchorAnchor} + ) +)`; +--- + + diff --git a/docs/src/components/components/infobubble/CustomThemeExample.astro b/docs/src/components/components/infobubble/CustomThemeExample.astro new file mode 100644 index 00000000..3cf36023 --- /dev/null +++ b/docs/src/components/components/infobubble/CustomThemeExample.astro @@ -0,0 +1,79 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + defaultBackgroundColorExpr?: string; + defaultBorderColorExpr?: string; + defaultTextColorExpr?: string; + defaultContentPaddingDp?: number; + defaultCornerRadiusDp?: number; + defaultTailSizeDp?: number; + darkBackgroundColorExpr?: string; + darkBorderColorExpr?: string; + darkTextColorExpr?: string; + darkContentPaddingDp?: number; + darkCornerRadiusDp?: number; + darkTailSizeDp?: number; +} + +const { + defaultBackgroundColorExpr = "Color.White", + defaultBorderColorExpr = "Color.Black", + defaultTextColorExpr = "Color.Black", + defaultContentPaddingDp = 8, + defaultCornerRadiusDp = 4, + defaultTailSizeDp = 8, + darkBackgroundColorExpr = "Color(0xFF2D2D2D)", + darkBorderColorExpr = "Color(0xFF555555)", + darkTextColorExpr = "Color.White", + darkContentPaddingDp = 12, + darkCornerRadiusDp = 8, + darkTailSizeDp = 10 +} = Astro.props; + +const code = `data class BubbleTheme( + val backgroundColor: Color, + val borderColor: Color, + val textColor: Color, + val contentPadding: Dp, + val cornerRadius: Dp, + val tailSize: Dp +) : java.io.Serializable + +val DefaultBubbleTheme = BubbleTheme( + backgroundColor = ${defaultBackgroundColorExpr}, + borderColor = ${defaultBorderColorExpr}, + textColor = ${defaultTextColorExpr}, + contentPadding = ${defaultContentPaddingDp}.dp, + cornerRadius = ${defaultCornerRadiusDp}.dp, + tailSize = ${defaultTailSizeDp}.dp +) + +val DarkBubbleTheme = BubbleTheme( + backgroundColor = ${darkBackgroundColorExpr}, + borderColor = ${darkBorderColorExpr}, + textColor = ${darkTextColorExpr}, + contentPadding = ${darkContentPaddingDp}.dp, + cornerRadius = ${darkCornerRadiusDp}.dp, + tailSize = ${darkTailSizeDp}.dp +) + +@Composable +fun ThemedInfoBubble( + marker: MarkerState, + theme: BubbleTheme = DefaultBubbleTheme, + content: @Composable () -> Unit +) { + InfoBubble( + marker = marker, + bubbleColor = theme.backgroundColor, + borderColor = theme.borderColor, + contentPadding = theme.contentPadding, + cornerRadius = theme.cornerRadius, + tailSize = theme.tailSize, + content = content + ) +}`; +--- + + diff --git a/docs/src/components/components/infobubble/DarkModeInfoBubbleExample.astro b/docs/src/components/components/infobubble/DarkModeInfoBubbleExample.astro new file mode 100644 index 00000000..091976a0 --- /dev/null +++ b/docs/src/components/components/infobubble/DarkModeInfoBubbleExample.astro @@ -0,0 +1,46 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + darkBackgroundColorExpr?: string; + lightBackgroundColorExpr?: string; + darkBorderColorExpr?: string; + lightBorderColorExpr?: string; + contentPaddingDp?: number; + cornerRadiusDp?: number; + darkTextColorExpr?: string; + lightTextColorExpr?: string; +} + +const { + darkBackgroundColorExpr = "Color(0xFF2D2D2D)", + lightBackgroundColorExpr = "Color.White", + darkBorderColorExpr = "Color(0xFF555555)", + lightBorderColorExpr = "Color.Black", + contentPaddingDp = 12, + cornerRadiusDp = 8, + darkTextColorExpr = "Color.White", + lightTextColorExpr = "Color.Black" +} = Astro.props; + +const code = `@Composable +fun DarkModeInfoBubble(marker: MarkerState) { + val isDarkTheme = isSystemInDarkTheme() + + InfoBubble( + marker = marker, + bubbleColor = if (isDarkTheme) ${darkBackgroundColorExpr} else ${lightBackgroundColorExpr}, + borderColor = if (isDarkTheme) ${darkBorderColorExpr} else ${lightBorderColorExpr}, + contentPadding = ${contentPaddingDp}.dp, + cornerRadius = ${cornerRadiusDp}.dp + ) { + Text( + text = marker.extra as? String ?: "", + color = if (isDarkTheme) ${darkTextColorExpr} else ${lightTextColorExpr}, + style = MaterialTheme.typography.bodyMedium + ) + } +}`; +--- + + diff --git a/docs/src/components/components/infobubble/DebugModeExample.astro b/docs/src/components/components/infobubble/DebugModeExample.astro new file mode 100644 index 00000000..23313dd7 --- /dev/null +++ b/docs/src/components/components/infobubble/DebugModeExample.astro @@ -0,0 +1,38 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForDebugLogging?: string; + commentForHighlight?: string; + markerIdLabelPrefix?: string; + positionLabelPrefix?: string; + commentForActualContent?: string; + debugBubbleColorExpr?: string; + debugBorderColorExpr?: string; +} + +const { + commentForDebugLogging = "Enable debug logging for InfoBubble positioning", + commentForHighlight = "Highlight for debugging", + markerIdLabelPrefix = "Marker ID", + positionLabelPrefix = "Position", + commentForActualContent = "Actual content", + debugBubbleColorExpr = "Color.Yellow.copy(alpha = 0.8f)", + debugBorderColorExpr = "Color.Red" +} = Astro.props; + +const code = `// ${commentForDebugLogging} +InfoBubble( + marker = marker, + bubbleColor = ${debugBubbleColorExpr}, // ${commentForHighlight} + borderColor = ${debugBorderColorExpr} +) { + Column { + Text("${markerIdLabelPrefix}: \${marker.id}") + Text("${positionLabelPrefix}: \${marker.position}") + // ${commentForActualContent} + } +}`; +--- + + diff --git a/docs/src/components/components/infobubble/EfficientUpdatesExample.astro b/docs/src/components/components/infobubble/EfficientUpdatesExample.astro new file mode 100644 index 00000000..ca28abba --- /dev/null +++ b/docs/src/components/components/infobubble/EfficientUpdatesExample.astro @@ -0,0 +1,35 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForGood?: string; + commentForStableId?: string; + commentForAvoid?: string; + commentForNewInstance?: string; +} + +const { + commentForGood = "Good: Use stable keys for markers", + commentForStableId = "Stable ID", + commentForAvoid = "Avoid: Creating new marker state on every recomposition", + commentForNewInstance = "New instance each time" +} = Astro.props; + +const code = `// ${commentForGood} +val markerStates = remember(markersData) { + markersData.map { data -> + MarkerState( + id = "marker_\${data.id}", // ${commentForStableId} + position = data.position, + extra = data + ) + } +} + +// ${commentForAvoid} +val markerStates = markersData.map { data -> + MarkerState(position = data.position, extra = data) // ${commentForNewInstance} +}`; +--- + + diff --git a/docs/src/components/components/infobubble/ImplementationTipsExample.astro b/docs/src/components/components/infobubble/ImplementationTipsExample.astro new file mode 100644 index 00000000..fd628367 --- /dev/null +++ b/docs/src/components/components/infobubble/ImplementationTipsExample.astro @@ -0,0 +1,44 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForStableReference?: string; + commentForEfficientUpdates?: string; + commentForLoadData?: string; + commentForAvoidHeavyComputation?: string; + commentForAvoidExpensiveOperations?: string; + commentForMoveToRemember?: string; +} + +const { + commentForStableReference = "Good: Stable marker reference", + commentForEfficientUpdates = "Good: Efficient content updates", + commentForLoadData = "Load additional data if needed", + commentForAvoidHeavyComputation = "Avoid: Heavy computation inside bubble content", + commentForAvoidExpensiveOperations = "Avoid expensive operations here", + commentForMoveToRemember = "Move to remember" +} = Astro.props; + +const code = `// ${commentForStableReference} +val markerState = remember(markerId) { + MarkerState(id = markerId, position = position) +} + +// ${commentForEfficientUpdates} +LaunchedEffect(selectedMarkerId) { + if (selectedMarkerId != null) { + // ${commentForLoadData} + } +} + +// ${commentForAvoidHeavyComputation} +InfoBubble(marker = marker) { + // ${commentForAvoidExpensiveOperations} + val processedData = remember(marker.extra) { + processData(marker.extra) // ${commentForMoveToRemember} + } + DisplayContent(processedData) +}`; +--- + + diff --git a/docs/src/components/components/infobubble/InfoBubbleSignature.astro b/docs/src/components/components/infobubble/InfoBubbleSignature.astro new file mode 100644 index 00000000..01f94d96 --- /dev/null +++ b/docs/src/components/components/infobubble/InfoBubbleSignature.astro @@ -0,0 +1,16 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `@Composable +fun InfoBubble( + marker: MarkerState, + bubbleColor: Color = Color.White, + borderColor: Color = Color.Black, + contentPadding: Dp = 8.dp, + cornerRadius: Dp = 4.dp, + tailSize: Dp = 8.dp, + content: @Composable () -> Unit +)`; +--- + + diff --git a/docs/src/components/components/infobubble/InteractiveBubbleExample.astro b/docs/src/components/components/infobubble/InteractiveBubbleExample.astro new file mode 100644 index 00000000..ebfd0530 --- /dev/null +++ b/docs/src/components/components/infobubble/InteractiveBubbleExample.astro @@ -0,0 +1,122 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + storeName?: string; + storeAddress?: string; + storePhone?: string; + storeType?: string; + cameraLatitude?: number; + cameraLongitude?: number; + markerLatitude?: number; + markerLongitude?: number; + markerColor?: string; + markerLabel?: string; + markerId?: string; + zoomLevel?: number; +} + +const { + storeName = "Coffee Shop", + storeAddress = "1-4, Hongo 4-Chome, Bunkyo-Ku", + storePhone = "+81 (555) 123-4567", + storeType = "coffee", + cameraLatitude = 35.70662, + cameraLongitude = 139.76378, + markerLatitude = 35.708106, + markerLongitude = 139.760823, + markerColor = "0xFF8B4513", + markerLabel = "☕", + markerId = "coffee-shop-marker", + zoomLevel = 16.0 +} = Astro.props; + +const code = `data class StoreInfo( + val name: String, + val address: String, + val phone: String, + val type: String +) : java.io.Serializable + +@Composable +fun InteractiveBubbleExample(modifier: Modifier = Modifier) { + val center = GeoPoint.fromLatLong(${cameraLatitude}, ${cameraLongitude}) + val camera = MapCameraPosition(position = center, zoom = ${zoomLevel}) + val mapViewState = rememberArcGISMapViewState(cameraPosition = camera) + + var selectedMarker by remember { mutableStateOf(null) } + val context = LocalContext.current + val onMarkerClick: OnMarkerEventHandler = { markerState -> + selectedMarker = markerState + } + + ArcGISMapView( + state = mapViewState, + modifier = modifier, + onMapClick = { selectedMarker = null } + ) { + val storeInfo = StoreInfo( + name = "${storeName}", + address = "${storeAddress}", + phone = "${storePhone}", + type = "${storeType}" + ) + + val markerState = MarkerState( + position = GeoPoint.fromLatLong(${markerLatitude}, ${markerLongitude}), + icon = DefaultIcon(fillColor = Color(${markerColor}), label = "${markerLabel}"), + extra = storeInfo, + id = "${markerId}", + onClick = onMarkerClick + ) + + Marker(markerState) + + selectedMarker?.let { marker -> + val store = marker.extra as? StoreInfo + store?.let { + InfoBubble( + marker = marker, + bubbleColor = Color.White, + borderColor = Color.Black, + contentPadding = 12.dp, + cornerRadius = 8.dp + ) { + Column(modifier = Modifier.width(250.dp)) { + Text( + text = store.name, + style = MaterialTheme.typography.titleMedium, + fontWeight = FontWeight.Bold + ) + Text( + text = store.address, + style = MaterialTheme.typography.bodySmall, + color = Color.Gray, + modifier = Modifier.padding(vertical = 4.dp) + ) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceEvenly + ) { + Button( + onClick = { + val intent = Intent(Intent.ACTION_DIAL).apply { + data = Uri.parse("tel:\${store.phone}") + } + context.startActivity(intent) + }, + colors = ButtonDefaults.buttonColors(containerColor = Color.Blue) + ) { + Icon(Icons.Default.Phone, contentDescription = "Call") + Text("Call", modifier = Modifier.padding(start = 4.dp)) + } + } + } + } + } + } + } +}`; +--- + + diff --git a/docs/src/components/components/infobubble/LifecycleManagementExample.astro b/docs/src/components/components/infobubble/LifecycleManagementExample.astro new file mode 100644 index 00000000..ee8a736c --- /dev/null +++ b/docs/src/components/components/infobubble/LifecycleManagementExample.astro @@ -0,0 +1,29 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForBubbleAppears?: string; + commentForContentPlaceholder?: string; + commentForBubbleDisappears?: string; + commentForAutoNull?: string; +} + +const { + commentForBubbleAppears = "Bubble appears when component is composed", + commentForContentPlaceholder = "Content", + commentForBubbleDisappears = "Bubble disappears when component is removed from composition", + commentForAutoNull = "This automatically happens when selectedMarker becomes null" +} = Astro.props; + +const code = `// ${commentForBubbleAppears} +selectedMarker?.let { marker -> + InfoBubble(marker = marker) { + // ${commentForContentPlaceholder} + } +} + +// ${commentForBubbleDisappears} +// ${commentForAutoNull}`; +--- + + diff --git a/docs/src/components/components/infobubble/ManualLifecycleExample.astro b/docs/src/components/components/infobubble/ManualLifecycleExample.astro new file mode 100644 index 00000000..3f363347 --- /dev/null +++ b/docs/src/components/components/infobubble/ManualLifecycleExample.astro @@ -0,0 +1,37 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `@Composable +fun ManualLifecycleExample() { + var showBubble by remember { mutableStateOf(false) } + val markerState = remember { /* marker state */ } + + LaunchedEffect(showBubble) { + if (showBubble) { + delay(3000) // Show for 3 seconds + showBubble = false + } + } + + // ${commentForMapViewUsage} + MapView(state = mapViewState) { + Marker(markerState) + + if (showBubble) { + InfoBubble(marker = markerState) { + Text("Auto-hiding bubble") + } + } + } +}`; +--- + + diff --git a/docs/src/components/components/infobubble/MemoryManagementExample.astro b/docs/src/components/components/infobubble/MemoryManagementExample.astro new file mode 100644 index 00000000..5d7e8250 --- /dev/null +++ b/docs/src/components/components/infobubble/MemoryManagementExample.astro @@ -0,0 +1,22 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForClearOnNavigate?: string; + commentForClearInfoBubble?: string; +} + +const { + commentForClearOnNavigate = "Clear selected marker when navigating away", + commentForClearInfoBubble = "Clear the InfoBubble" +} = Astro.props; + +const code = `// ${commentForClearOnNavigate} +DisposableEffect(Unit) { + onDispose { + selectedMarker = null // ${commentForClearInfoBubble} + } +}`; +--- + + diff --git a/docs/src/components/components/infobubble/MultipleBubblesExample.astro b/docs/src/components/components/infobubble/MultipleBubblesExample.astro new file mode 100644 index 00000000..61732a05 --- /dev/null +++ b/docs/src/components/components/infobubble/MultipleBubblesExample.astro @@ -0,0 +1,118 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; + commentForTapToClose?: string; + marker1Latitude?: number; + marker1Longitude?: number; + marker1Name?: string; + marker1ColorExpr?: string; + marker2Latitude?: number; + marker2Longitude?: number; + marker2Name?: string; + marker2ColorExpr?: string; + marker3Latitude?: number; + marker3Longitude?: number; + marker3Name?: string; + marker3ColorExpr?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView", + commentForTapToClose = "Tap to close", + marker1Latitude = 37.7749, + marker1Longitude = -122.4194, + marker1Name = "Restaurant A", + marker1ColorExpr = "Color.Red", + marker2Latitude = 37.7849, + marker2Longitude = -122.4094, + marker2Name = "Hotel B", + marker2ColorExpr = "Color.Blue", + marker3Latitude = 37.7649, + marker3Longitude = -122.4294, + marker3Name = "Shop C", + marker3ColorExpr = "Color.Green" +} = Astro.props; + +const code = `@Composable +fun MultipleBubblesExample() { + val mapViewState = rememberGoogleMapViewState() + var selectedMarkers by remember { mutableStateOf(setOf()) } + val onMarkerClick: OnMarkerEventHandler = { markerState -> + selectedMarkers = if (selectedMarkers.contains(markerState.id)) { + selectedMarkers - markerState.id // Deselect + } else { + selectedMarkers + markerState.id // Select + } + } + + val markerData = remember { + listOf( + Triple( + GeoPoint.fromLatLong(${marker1Latitude}, ${marker1Longitude}), + "${marker1Name}", + ${marker1ColorExpr} + ), + Triple( + GeoPoint.fromLatLong(${marker2Latitude}, ${marker2Longitude}), + "${marker2Name}", + ${marker2ColorExpr} + ), + Triple( + GeoPoint.fromLatLong(${marker3Latitude}, ${marker3Longitude}), + "${marker3Name}", + ${marker3ColorExpr} + ) + ) + } + + val markerStates = remember { + markerData.mapIndexed { index, (position, name, color) -> + MarkerState( + id = "marker_\$index", + position = position, + icon = DefaultIcon(fillColor = color, label = "\${index + 1}"), + extra = name, + onClick = onMarkerClick + ) + } + } + + // ${commentForMapViewUsage} + MapView( + state = mapViewState, + onMapClick = { + selectedMarkers = emptySet() // Clear all selections + } + ) { + markerStates.forEach { markerState -> + Marker(markerState) + + // Show bubble if marker is selected + if (selectedMarkers.contains(markerState.id)) { + InfoBubble( + marker = markerState, + bubbleColor = Color.White, + borderColor = Color.Black + ) { + Column { + Text( + text = markerState.extra as String, + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.Bold + ) + Text( + text = "${commentForTapToClose}", + style = MaterialTheme.typography.bodySmall, + color = Color.Gray + ) + } + } + } + } + } +}`; +--- + + diff --git a/docs/src/components/components/infobubble/RichContentInfoBubbleExample.astro b/docs/src/components/components/infobubble/RichContentInfoBubbleExample.astro new file mode 100644 index 00000000..dd68df44 --- /dev/null +++ b/docs/src/components/components/infobubble/RichContentInfoBubbleExample.astro @@ -0,0 +1,115 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + locationName?: string; + locationDescription?: string; + locationRating?: number; + latitude?: number; + longitude?: number; + markerLabel?: string; + markerId?: string; + zoomLevel?: number; + markerFillColorExpr?: string; +} + +const { + locationName = "Golden Gate Park", + locationDescription = "A large urban park with gardens, museums, and recreational areas.", + locationRating = 4.5, + latitude = 37.7694, + longitude = -122.4862, + markerLabel = "🌳", + markerId = "park-marker", + zoomLevel = 13.0, + markerFillColorExpr = "Color.Green" +} = Astro.props; + +const code = `data class LocationInfo( + val name: String, + val description: String, + val rating: Float, + val imageUrl: String? = null +) : java.io.Serializable + +@Composable +fun RichContentBubbleExample() { + var selectedMarker by remember { mutableStateOf(null) } + + val center = GeoPoint.fromLatLong(${latitude}, ${longitude}) + val camera = MapCameraPosition(position = center, zoom = ${zoomLevel}) + val mapViewState = rememberHereMapViewState(cameraPosition = camera) + val onMarkerClick: OnMarkerEventHandler = { markerState -> + selectedMarker = markerState + } + + HereMapView( + modifier = modifier, + state = mapViewState, + onMapClick = { selectedMarker = null } + ) { + val locationInfo = LocationInfo( + name = "${locationName}", + description = "${locationDescription}", + rating = ${locationRating}f + ) + + val markerState = MarkerState( + position = GeoPoint.fromLatLong(${latitude}, ${longitude}), + icon = DefaultIcon(fillColor = ${markerFillColorExpr}, label = "${markerLabel}"), + extra = locationInfo, + id = "${markerId}", + onClick = onMarkerClick + ) + + Marker(markerState) + + selectedMarker?.let { marker -> + val info = marker.extra as? LocationInfo + info?.let { + InfoBubble( + marker = marker, + bubbleColor = MaterialTheme.colorScheme.background, + borderColor = Color.Gray, + contentPadding = 16.dp, + cornerRadius = 12.dp + ) { + Column(modifier = Modifier.width(200.dp)) { + Text( + text = info.name, + style = MaterialTheme.typography.headlineSmall, + color = MaterialTheme.colorScheme.primary, + fontWeight = FontWeight.Bold + ) + Spacer(modifier = Modifier.height(8.dp)) + Text( + text = info.description, + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.primary + ) + Spacer(modifier = Modifier.height(8.dp)) + Row(verticalAlignment = Alignment.CenterVertically) { + repeat(5) { index -> + Icon( + Icons.Default.Star, + contentDescription = null, + tint = if (index < info.rating.toInt()) Color.Yellow else Color.Gray, + modifier = Modifier.size(16.dp) + ) + } + Text( + text = " \${info.rating}/5", + color = MaterialTheme.colorScheme.primary, + style = MaterialTheme.typography.bodySmall, + modifier = Modifier.padding(start = 4.dp) + ) + } + } + } + } + } + } +}`; +--- + + diff --git a/docs/src/components/components/infobubble/RightInfoBubbleMapExample.astro b/docs/src/components/components/infobubble/RightInfoBubbleMapExample.astro new file mode 100644 index 00000000..99247ce0 --- /dev/null +++ b/docs/src/components/components/infobubble/RightInfoBubbleMapExample.astro @@ -0,0 +1,236 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + centerLatitude?: number; + centerLongitude?: number; + zoomLevel?: number; + marker1Latitude?: number; + marker1Longitude?: number; + marker2Latitude?: number; + marker2Longitude?: number; + mapLoadedMessage?: string; + markerDragStartMessagePrefix?: string; + markerDragMessagePrefix?: string; + markerDragEndMessagePrefix?: string; + commentForMapClickClear?: string; + commentForInteractiveMarkers?: string; + commentForSelectedMarkerInfo?: string; + commentForRightSideTailExample?: string; +} + +const { + centerLatitude = 37.7749, + centerLongitude = -122.4194, + zoomLevel = 13.0, + marker1Latitude = 37.7749, + marker1Longitude = -122.4194, + marker2Latitude = 37.7849, + marker2Longitude = -122.4094, + mapLoadedMessage = 'Map loaded and ready', + markerDragStartMessagePrefix = 'Started dragging marker', + markerDragMessagePrefix = 'Dragging marker to', + markerDragEndMessagePrefix = 'Finished dragging marker', + commentForMapClickClear = 'Clear selection when the map is clicked', + commentForInteractiveMarkers = 'Interactive map content with markers', + commentForSelectedMarkerInfo = 'Show information for the selected marker', + commentForRightSideTailExample = 'Custom bubble with right-side tail', +} = Astro.props; + +const code = `@Composable +fun RightInfoBubbleMapExample(modifier: Modifier = Modifier) { + val center = GeoPoint.fromLatLong(${centerLatitude}, ${centerLongitude}) + val mapViewState = + rememberMapLibreMapViewState( + cameraPosition = + MapCameraPosition( + position = center, + zoom = ${zoomLevel}, + ), + ) + var selectedMarker by remember { mutableStateOf(null) } + val onMarkerClick: OnMarkerEventHandler = { markerState -> + selectedMarker = markerState + } + val onMarkerDragStart: OnMarkerEventHandler = { markerState -> + println("${markerDragStartMessagePrefix}: ${'$'}{markerState.id}") + } + val onMarkerDrag: OnMarkerEventHandler = { markerState -> + println("${markerDragMessagePrefix}: ${'$'}{markerState.position}") + } + val onMarkerDragEnd: OnMarkerEventHandler = { markerState -> + println("${markerDragEndMessagePrefix}: ${'$'}{markerState.id}") + } + + val markerState1 by remember { + mutableStateOf( + MarkerState( + id = "marker1", + position = GeoPoint.fromLatLong(${marker1Latitude}, ${marker1Longitude}), + icon = + DefaultIcon( + fillColor = Color.Blue, + infoAnchor = Offset(0.5f, 0.25f), + label = "1", + ), + draggable = true, + onClick = onMarkerClick, + onDragStart = onMarkerDragStart, + onDrag = onMarkerDrag, + onDragEnd = onMarkerDragEnd, + ), + ) + } + val markerState2 by remember { + mutableStateOf( + MarkerState( + id = "marker2", + position = GeoPoint.fromLatLong(${marker2Latitude}, ${marker2Longitude}), + icon = + DefaultIcon( + fillColor = Color.Red, + infoAnchor = Offset(0.5f, 0.25f), + label = "2", + ), + onClick = onMarkerClick, + ), + ) + } + + MapLibreMapView( + state = mapViewState, + onMapLoaded = { + println("${mapLoadedMessage}") + }, + onMapClick = { geoPoint -> + selectedMarker = null // ${commentForMapClickClear} + } + ) { + // ${commentForInteractiveMarkers} + Marker(markerState1) + Marker(markerState2) + + // ${commentForSelectedMarkerInfo} + selectedMarker?.let { marker -> + val text = GeoPoint.from(marker.position).toUrlValue(6) + // ${commentForRightSideTailExample} + InfoBubbleCustom( + marker = marker, + tailOffset = Offset(0f, 0.5f), // attach at center-left of the bubble + ) { + RightTailInfoBubble( + bubbleColor = Color.White, + borderColor = Color.Black, + ) { + Text( + text = text, + color = MaterialTheme.colorScheme.primary, + ) + } + } + } + } +} + +@Composable +private fun RightTailInfoBubble( + bubbleColor: Color, + borderColor: Color, + contentPadding: androidx.compose.ui.unit.Dp = 8.dp, + cornerRadius: androidx.compose.ui.unit.Dp = 4.dp, + tailSize: androidx.compose.ui.unit.Dp = 8.dp, + content: @Composable () -> Unit, +) { + Box(modifier = Modifier.wrapContentSize()) { + Canvas(modifier = Modifier.matchParentSize()) { + val width = size.width + val height = size.height + val tail = tailSize.toPx() + val corner = cornerRadius.toPx() + + val path = + Path().apply { + // start at top-left (after tail area) + moveTo(tail + 2 * corner, 0f) + lineTo(width - 2 * corner, 0f) + // top-right corner + arcTo( + rect = + Rect( + topLeft = Offset(width - 2 * corner, 0f), + bottomRight = Offset(width, 2 * corner), + ), + startAngleDegrees = -90f, + sweepAngleDegrees = 90f, + forceMoveTo = false, + ) + // right edge + lineTo(width, height - 2 * corner) + // bottom-right corner + arcTo( + rect = + Rect( + topLeft = Offset(width - 2 * corner, height - 2 * corner), + bottomRight = Offset(width, height), + ), + startAngleDegrees = 0f, + sweepAngleDegrees = 90f, + forceMoveTo = false, + ) + // bottom edge towards left (before tail) + lineTo(tail + 2 * corner, height) + // bottom-left corner (before tail) + arcTo( + rect = + Rect( + topLeft = Offset(tail, height - 2 * corner), + bottomRight = Offset(tail + 2 * corner, height), + ), + startAngleDegrees = 90f, + sweepAngleDegrees = 90f, + forceMoveTo = false, + ) + // left edge up to tail bottom + lineTo(tail, height / 2 + tail / 2) + // Tail on left side + lineTo(0f, height / 2) + lineTo(tail, height / 2 - tail / 2) + // left edge up to top-left corner + lineTo(tail, 2 * corner) + // top-left corner + arcTo( + rect = + Rect( + topLeft = Offset(tail, 0f), + bottomRight = Offset(tail + 2 * corner, 2 * corner), + ), + startAngleDegrees = 180f, + sweepAngleDegrees = 90f, + forceMoveTo = false, + ) + close() + } + + drawPath(path, color = bubbleColor, style = Fill) + drawPath(path, color = borderColor, style = Stroke(width = 2f)) + } + + Box( + modifier = + Modifier + .padding( + start = contentPadding + tailSize, + top = contentPadding, + bottom = contentPadding, + end = contentPadding, + ).wrapContentSize() + .clip(RoundedCornerShape(cornerRadius)), + ) { + content() + } + } +} +`; +--- + + diff --git a/docs/src/components/components/infobubble/SimpleInfoBubbleExample.astro b/docs/src/components/components/infobubble/SimpleInfoBubbleExample.astro new file mode 100644 index 00000000..c661e885 --- /dev/null +++ b/docs/src/components/components/infobubble/SimpleInfoBubbleExample.astro @@ -0,0 +1,79 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + centerLatitude?: number; + centerLongitude?: number; + zoomLevel?: number; + markerFillColorExpr?: string; + markerLabel?: string; + markerExtra?: string; + markerId?: string; + contentPaddingDp?: number; + cornerRadiusDp?: number; + tailSizeDp?: number; + textColorExpr?: string; + textStyleExpr?: string; +} + +const { + centerLatitude = 52.5163, + centerLongitude = 13.3777, + zoomLevel = 13.0, + markerFillColorExpr = "Color.Green", + markerLabel = "POI", + markerExtra = "Brandenburg Gate", + markerId = "poi-marker", + contentPaddingDp = 12, + cornerRadiusDp = 8, + tailSizeDp = 10, + textColorExpr = "Color.Black", + textStyleExpr = "MaterialTheme.typography.bodyLarge" +} = Astro.props; + +const code = `@Composable +fun SimpleInfoBubbleExample() { + val center = GeoPoint.fromLatLong(${centerLatitude}, ${centerLongitude}) + + val camera = MapCameraPosition(position = center, zoom = ${zoomLevel}) + val mapViewState = rememberHereMapViewState(cameraPosition = camera) + + var selectedMarker by remember { mutableStateOf(null) } + val onMarkerClick: OnMarkerEventHandler = { markerState -> + selectedMarker = markerState + } + + HereMapView( + modifier = modifier, + state = mapViewState, + onMapClick = { selectedMarker = null } + ) { + val markerState = MarkerState( + position = center, + icon = DefaultIcon(fillColor = ${markerFillColorExpr}, label = "${markerLabel}"), + extra = "${markerExtra}", + id = "${markerId}", + onClick = onMarkerClick + ) + + Marker(markerState) + + selectedMarker?.let { marker -> + InfoBubble( + marker = marker, + contentPadding = ${contentPaddingDp}.dp, + cornerRadius = ${cornerRadiusDp}.dp, + tailSize = ${tailSizeDp}.dp + ) { + Text( + text = marker.extra as? String ?: "", + color = ${textColorExpr}, + style = ${textStyleExpr} + ) + } + } + } +}`; +--- + + diff --git a/docs/src/components/components/mapviewcomponent/AdvancedMapEventHandlingExample.astro b/docs/src/components/components/mapviewcomponent/AdvancedMapEventHandlingExample.astro new file mode 100644 index 00000000..ed2b72e5 --- /dev/null +++ b/docs/src/components/components/mapviewcomponent/AdvancedMapEventHandlingExample.astro @@ -0,0 +1,109 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + centerLatitude?: number; + centerLongitude?: number; + zoomLevel?: number; + mapLoadedMessage?: string; + mapClickedPrefix?: string; + cameraMoveStartMessage?: string; + cameraMovePrefix?: string; + cameraMoveEndMessage?: string; + markerClickedPrefix?: string; + centerMarkerLabel?: string; + centerMarkerExtra?: string; + centerMarkerFillColorExpr?: string; + centerCircleRadiusMeters?: number; + centerCircleStrokeColorExpr?: string; + centerCircleFillColorExpr?: string; + clickedMarkerLabel?: string; + clickedMarkerExtra?: string; + clickedMarkerFillColorExpr?: string; + commentForCenterMarkerAndCircle?: string; + commentForClickedMarker?: string; +} + +const { + centerLatitude = 37.7749, + centerLongitude = -122.4194, + zoomLevel = 13.0, + mapLoadedMessage = 'Map loaded successfully', + mapClickedPrefix = 'Map clicked at', + cameraMoveStartMessage = 'Camera move started', + cameraMovePrefix = 'Camera position', + cameraMoveEndMessage = 'Camera move ended', + markerClickedPrefix = 'Marker clicked', + centerMarkerLabel = 'Center', + centerMarkerExtra = 'Center marker', + centerMarkerFillColorExpr = 'Color.Red', + centerCircleRadiusMeters = 1000.0, + centerCircleStrokeColorExpr = 'Color.Blue', + centerCircleFillColorExpr = 'Color.Blue.copy(alpha = 0.2f)', + clickedMarkerLabel = 'Clicked', + clickedMarkerExtra = 'Clicked point', + clickedMarkerFillColorExpr = 'Color.Green', + commentForCenterMarkerAndCircle = 'Show marker and circle', + commentForClickedMarker = 'Show marker at clicked position', +} = Astro.props; + +const code = `@Composable +fun AdvancedMapExample() { + val center = GeoPoint.fromLatLong(${centerLatitude}, ${centerLongitude}) + val mapViewState = rememberGoogleMapViewState( + cameraPosition = MapCameraPosition(position = center, zoom = ${zoomLevel}) + ) + + var clickedPoint by remember { mutableStateOf(null) } + val onMarkerClick: (MarkerState) -> Unit = { markerState -> + println("${markerClickedPrefix}: \${markerState.extra}") + } + + GoogleMapView( + state = mapViewState, + onMapLoaded = { + println("${mapLoadedMessage}") + }, + onMapClick = { geoPoint -> + clickedPoint = geoPoint + println("${mapClickedPrefix}: \${geoPoint.latitude}, \${geoPoint.longitude}") + }, + onCameraMoveStart = { + println("${cameraMoveStartMessage}") + }, + onCameraMove = { cameraPosition -> + println("${cameraMovePrefix}: \${cameraPosition.position}") + }, + onCameraMoveEnd = { + println("${cameraMoveEndMessage}") + } + ) { + // ${commentForCenterMarkerAndCircle} + Marker( + position = center, + icon = DefaultIcon(label = "${centerMarkerLabel}", fillColor = ${centerMarkerFillColorExpr}), + extra = "${centerMarkerExtra}", + onClick = onMarkerClick + ) + + Circle( + center = center, + radiusMeters = ${centerCircleRadiusMeters}, + strokeColor = ${centerCircleStrokeColorExpr}, + fillColor = ${centerCircleFillColorExpr} + ) + + // ${commentForClickedMarker} + clickedPoint?.let { point -> + Marker( + position = point, + icon = DefaultIcon(label = "${clickedMarkerLabel}", fillColor = ${clickedMarkerFillColorExpr}), + extra = "${clickedMarkerExtra}", + onClick = onMarkerClick + ) + } + } +}`; +--- + + diff --git a/docs/src/components/components/mapviewcomponent/GoogleMapsExample.astro b/docs/src/components/components/mapviewcomponent/GoogleMapsExample.astro new file mode 100644 index 00000000..85c16633 --- /dev/null +++ b/docs/src/components/components/mapviewcomponent/GoogleMapsExample.astro @@ -0,0 +1,57 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + centerLatitude?: number; + centerLongitude?: number; + mapClickPrefix?: string; + markerClickPrefix?: string; + markerLabel?: string; + markerExtra?: string; + circleRadiusMeters?: number; + circleStrokeColorExpr?: string; + circleFillColorExpr?: string; +} + +const { + centerLatitude = 37.7749, + centerLongitude = -122.4194, + mapClickPrefix = 'Map clicked at', + markerClickPrefix = 'Marker clicked', + markerLabel = 'SF', + markerExtra = 'San Francisco', + circleRadiusMeters = 1000.0, + circleStrokeColorExpr = 'Color.Blue', + circleFillColorExpr = 'Color.Blue.copy(alpha = 0.3f)', +} = Astro.props; + +const code = `@Composable +fun GoogleMapsExample() { + val mapViewState = rememberGoogleMapViewState() + + GoogleMapView( + state = mapViewState, + onMapClick = { geoPoint -> + println("${mapClickPrefix}: \${geoPoint.latitude}, \${geoPoint.longitude}") + } + ) { + Marker( + position = GeoPoint.fromLatLong(${centerLatitude}, ${centerLongitude}), + icon = DefaultIcon(label = "${markerLabel}"), + extra = "${markerExtra}", + onClick = { markerState -> + println("${markerClickPrefix}: \${markerState.extra}") + } + ) + + Circle( + center = GeoPoint.fromLatLong(${centerLatitude}, ${centerLongitude}), + radiusMeters = ${circleRadiusMeters}, + strokeColor = ${circleStrokeColorExpr}, + fillColor = ${circleFillColorExpr} + ) + } +}`; +--- + + diff --git a/docs/src/components/components/mapviewcomponent/MapViewComponentSignaturesTabs.astro b/docs/src/components/components/mapviewcomponent/MapViewComponentSignaturesTabs.astro new file mode 100644 index 00000000..50508a8b --- /dev/null +++ b/docs/src/components/components/mapviewcomponent/MapViewComponentSignaturesTabs.astro @@ -0,0 +1,78 @@ +--- +import { Tabs, TabItem, Code } from '@astrojs/starlight/components'; + +const googleMapsCode = `GoogleMapView( + state: GoogleMapViewState, + modifier: Modifier = Modifier, + onMapLoaded: OnMapLoadedHandler? = null, + onMapClick: OnMapEventHandler? = null, + onCameraMoveStart: OnCameraMoveHandler? = null, + onCameraMove: OnCameraMoveHandler? = null, + onCameraMoveEnd: OnCameraMoveHandler? = null, + content: (@Composable () -> Unit)? = null +)`; + + +const mapboxCode = `MapboxMapView( + state: MapboxViewState, + modifier: Modifier = Modifier, + onMapLoaded: OnMapLoadedHandler? = null, + onMapClick: OnMapEventHandler? = null, + onCameraMoveStart: OnCameraMoveHandler? = null, + onCameraMove: OnCameraMoveHandler? = null, + onCameraMoveEnd: OnCameraMoveHandler? = null, + content: (@Composable () -> Unit)? = null +)`; + + +const hereMapCode = `HereMapView( + state: HereViewState, + modifier: Modifier = Modifier, + onMapLoaded: OnMapLoadedHandler? = null, + onMapClick: OnMapEventHandler? = null, + onCameraMoveStart: OnCameraMoveHandler? = null, + onCameraMove: OnCameraMoveHandler? = null, + onCameraMoveEnd: OnCameraMoveHandler? = null, + content: (@Composable () -> Unit)? = null +)`; + +const mapLibreCode = `MapLibreMapView( + state: MapLibreViewState, + modifier: Modifier = Modifier, + onMapLoaded: OnMapLoadedHandler? = null, + onMapClick: OnMapEventHandler? = null, + onCameraMoveStart: OnCameraMoveHandler? = null, + onCameraMove: OnCameraMoveHandler? = null, + onCameraMoveEnd: OnCameraMoveHandler? = null, + content: (@Composable () -> Unit)? = null +)`; + +const arcGISMapCode = `ArcGISMapView( + state: ArcGISMapViewState, + modifier: Modifier = Modifier, + onMapLoaded: OnMapLoadedHandler? = null, + onMapClick: OnMapEventHandler? = null, + onCameraMoveStart: OnCameraMoveHandler? = null, + onCameraMove: OnCameraMoveHandler? = null, + onCameraMoveEnd: OnCameraMoveHandler? = null, + content: (@Composable () -> Unit)? = null +)`; +--- + + + + + + + + + + + + + + + + + + diff --git a/docs/src/components/components/mapviewcomponent/MapboxExample.astro b/docs/src/components/components/mapviewcomponent/MapboxExample.astro new file mode 100644 index 00000000..09a9f305 --- /dev/null +++ b/docs/src/components/components/mapviewcomponent/MapboxExample.astro @@ -0,0 +1,73 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + centerLatitude?: number; + centerLongitude?: number; + zoomLevel?: number; + mapClickPrefix?: string; + markerLabel?: string; + markerExtra?: string; + markerLatitude?: number; + markerLongitude?: number; + polylinePoint1Latitude?: number; + polylinePoint1Longitude?: number; + polylinePoint2Latitude?: number; + polylinePoint2Longitude?: number; + polylinePoint3Latitude?: number; + polylinePoint3Longitude?: number; + polylineStrokeColorExpr?: string; + polylineStrokeWidthDp?: number; +} + +const { + centerLatitude = 37.7749, + centerLongitude = -122.4194, + zoomLevel = 13.0, + mapClickPrefix = 'Map clicked at', + markerLabel = 'MB', + markerExtra = 'Mapbox marker', + markerLatitude = 37.7749, + markerLongitude = -122.4194, + polylinePoint1Latitude = 37.7749, + polylinePoint1Longitude = -122.4194, + polylinePoint2Latitude = 37.7849, + polylinePoint2Longitude = -122.4094, + polylinePoint3Latitude = 37.7949, + polylinePoint3Longitude = -122.3994, + polylineStrokeColorExpr = 'Color.Red', + polylineStrokeWidthDp = 3, +} = Astro.props; + +const code = `@Composable +fun MapboxExample() { + val center = GeoPoint.fromLatLong(${centerLatitude}, ${centerLongitude}) + val camera = MapCameraPosition(position = center, zoom = ${zoomLevel}) + val mapViewState = rememberMapboxMapViewState(cameraPosition = camera) + + MapboxMapView( + state = mapViewState, + onMapClick = { geoPoint -> + println("${mapClickPrefix}: \${geoPoint.latitude}, \${geoPoint.longitude}") + } + ) { + Marker( + position = GeoPoint.fromLatLong(${markerLatitude}, ${markerLongitude}), + icon = DefaultIcon(label = "${markerLabel}"), + extra = "${markerExtra}" + ) + + Polyline( + points = listOf( + GeoPoint.fromLatLong(${polylinePoint1Latitude}, ${polylinePoint1Longitude}), + GeoPoint.fromLatLong(${polylinePoint2Latitude}, ${polylinePoint2Longitude}), + GeoPoint.fromLatLong(${polylinePoint3Latitude}, ${polylinePoint3Longitude}) + ), + strokeColor = ${polylineStrokeColorExpr}, + strokeWidth = ${polylineStrokeWidthDp}.dp + ) + } +}`; +--- + + diff --git a/docs/src/components/components/mapviewcomponent/ProviderIndependentMapContentExample.astro b/docs/src/components/components/mapviewcomponent/ProviderIndependentMapContentExample.astro new file mode 100644 index 00000000..8efd4ae1 --- /dev/null +++ b/docs/src/components/components/mapviewcomponent/ProviderIndependentMapContentExample.astro @@ -0,0 +1,62 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + markerLatitude?: number; + markerLongitude?: number; + markerLabel?: string; + markerExtra?: string; + radiusMeters?: number; + strokeColorExpr?: string; + fillColorExpr?: string; + commentForReusableContent?: string; + commentForSameContentDifferentSdk?: string; +} + +const { + markerLatitude = 37.7749, + markerLongitude = -122.4194, + markerLabel = 'Point', + markerExtra = 'Common marker', + radiusMeters = 500.0, + strokeColorExpr = 'Color.Green', + fillColorExpr = 'Color.Green.copy(alpha = 0.2f)', + commentForReusableContent = 'Reusable content', + commentForSameContentDifferentSdk = 'Same content, different map SDK', +} = Astro.props; + +const code = `@Composable +fun MapContent() { + Marker( + position = GeoPoint.fromLatLong(${markerLatitude}, ${markerLongitude}), + icon = DefaultIcon(label = "${markerLabel}"), + extra = "${markerExtra}" + ) + + Circle( + center = GeoPoint.fromLatLong(${markerLatitude}, ${markerLongitude}), + radiusMeters = ${radiusMeters}, + strokeColor = ${strokeColorExpr}, + fillColor = ${fillColorExpr} + ) +} + +@Composable +fun GoogleMapsScreen() { + val state = rememberGoogleMapViewState() + GoogleMapView(state = state) { + MapContent() // ${commentForReusableContent} + } +} + +@Composable +fun MapboxScreen() { + val state = remember { MapboxViewState() } + MapboxMapView(state = state) { + MapContent() // ${commentForSameContentDifferentSdk} + } +}`; +--- + + + diff --git a/docs/src/components/components/mapviewstate/CameraControlExample.astro b/docs/src/components/components/mapviewstate/CameraControlExample.astro new file mode 100644 index 00000000..f33f4bc7 --- /dev/null +++ b/docs/src/components/components/mapviewstate/CameraControlExample.astro @@ -0,0 +1,36 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `@Composable +fun CameraControlExample() { + val london = GeoPoint.fromLatLong(51.4985, 0.0) + val camera = MapCameraPosition(position = london, zoom = 8.0) + val mapViewState = rememberHereMapViewState(cameraPosition = camera) + + Column(modifier = modifier) { + Button( + onClick = { + val sanFrancisco = GeoPoint.fromLatLong(37.7749, -122.4194) + mapViewState.moveCameraTo( + position = sanFrancisco, + durationMillis = 3000 + ) + } + ) { + Text("Move to San Francisco") + } + + HereMapView( + modifier = Modifier.fillMaxSize(), + state = mapViewState, + onCameraMoveEnd = { + println("Camera movement completed") + } + ) { + // Marker, Polygon, etc + } + } +}`; +--- + + diff --git a/docs/src/components/components/mapviewstate/MapDesignSwitchExample.astro b/docs/src/components/components/mapviewstate/MapDesignSwitchExample.astro new file mode 100644 index 00000000..c2d74eac --- /dev/null +++ b/docs/src/components/components/mapviewstate/MapDesignSwitchExample.astro @@ -0,0 +1,51 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `@Composable +fun MapDesignSwitchExample() { + val london = GeoPoint.fromLatLong(51.4985, 0.0) + val camera = MapCameraPosition(position = london, zoom = 8.0) + val mapViewState = rememberHereMapViewState( + cameraPosition = camera, + mapDesign = HereMapDesign.NormalDay + ) + + Column(modifier = modifier) { + Row(modifier = Modifier.fillMaxWidth()) { + Button( + onClick = { + mapViewState.mapDesignType = HereMapDesign.NormalDay + } + ) { + Text("NormalDay") + } + Spacer(modifier = Modifier.width(20.dp)) + + Button( + onClick = { + mapViewState.mapDesignType = HereMapDesign.NormalNight + } + ) { + Text("NormalNight") + } + + Spacer(modifier = Modifier.width(20.dp)) + Button( + onClick = { + mapViewState.mapDesignType = HereMapDesign.HybridDay + } + ) { + Text("HYBRID_DAY") + } + } + + HereMapView( + state = mapViewState + ) { + // Marker, Polyline... etc, + } + } +}`; +--- + + diff --git a/docs/src/components/components/mapviewstate/MapViewStateEventHandlingExample.astro b/docs/src/components/components/mapviewstate/MapViewStateEventHandlingExample.astro new file mode 100644 index 00000000..cda57185 --- /dev/null +++ b/docs/src/components/components/mapviewstate/MapViewStateEventHandlingExample.astro @@ -0,0 +1,33 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; + commentForMapContent?: string; + mapLoadedMessage?: string; + mapClickPrefix?: string; +} + +const { + commentForMapViewUsage = 'Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView', + commentForMapContent = 'Map content', + mapLoadedMessage = 'Map loaded successfully', + mapClickPrefix = 'Map clicked at', +} = Astro.props; + +const code = `// ${commentForMapViewUsage} +MapView( + state = mapViewState, + onMapLoaded = { + println("${mapLoadedMessage}") + }, + onMapClick = { geoPoint -> + println("${mapClickPrefix}: \${geoPoint.latitude}, \${geoPoint.longitude}") + } +) { + // ${commentForMapContent} +}`; +--- + + + diff --git a/docs/src/components/components/mapviewstate/MoveCameraToCameraPositionSignature.astro b/docs/src/components/components/mapviewstate/MoveCameraToCameraPositionSignature.astro new file mode 100644 index 00000000..ca2d64f6 --- /dev/null +++ b/docs/src/components/components/mapviewstate/MoveCameraToCameraPositionSignature.astro @@ -0,0 +1,11 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `fun moveCameraTo( + cameraPosition: MapCameraPosition, + durationMillis: Long? = 0, +)`; +--- + + + diff --git a/docs/src/components/components/mapviewstate/MoveCameraToGeoPointSignature.astro b/docs/src/components/components/mapviewstate/MoveCameraToGeoPointSignature.astro new file mode 100644 index 00000000..d39b04a1 --- /dev/null +++ b/docs/src/components/components/mapviewstate/MoveCameraToGeoPointSignature.astro @@ -0,0 +1,11 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `fun moveCameraTo( + position: GeoPoint, + durationMillis: Long? = 0, +)`; +--- + + + diff --git a/docs/src/components/components/marker/BasicMarkerExample.astro b/docs/src/components/components/marker/BasicMarkerExample.astro new file mode 100644 index 00000000..e43820af --- /dev/null +++ b/docs/src/components/components/marker/BasicMarkerExample.astro @@ -0,0 +1,23 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `// ${commentForMapViewUsage} +MapView(state = mapViewState) { + Marker( + position = GeoPoint.fromLatLong(37.7749, -122.4194), + extra = "San Francisco", + id = "san-francisco-marker" + ) +}`; +--- + + + diff --git a/docs/src/components/components/marker/CustomIconMarkerExample.astro b/docs/src/components/components/marker/CustomIconMarkerExample.astro new file mode 100644 index 00000000..8c7ebaa9 --- /dev/null +++ b/docs/src/components/components/marker/CustomIconMarkerExample.astro @@ -0,0 +1,30 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `${commentForMapViewUsage.startsWith("Replace") ? "// " + commentForMapViewUsage : commentForMapViewUsage} +MapView(state = mapViewState) { + Marker( + position = GeoPoint.fromLatLong(37.7749, -122.4194), + icon = DefaultIcon( + scale = 1.5f, + label = "SF", + fillColor = Color.Blue, + strokeColor = Color.White, + strokeWidth = 2.dp + ), + extra = "San Francisco with custom icon", + id = "custom-sf-marker" + ) +}`; +--- + + + diff --git a/docs/src/components/components/marker/DefaultIconSignature.astro b/docs/src/components/components/marker/DefaultIconSignature.astro new file mode 100644 index 00000000..684f8424 --- /dev/null +++ b/docs/src/components/components/marker/DefaultIconSignature.astro @@ -0,0 +1,17 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `DefaultIcon( + scale: Float = 1.0f, + label: String? = null, + fillColor: Color = Color.Red, + strokeColor: Color = Color.Black, + strokeWidth: Dp = 1.dp, + labelTextColor: Color = Color.White, + labelStrokeColor: Color? = null, + debug: Boolean = false +)`; +--- + + + diff --git a/docs/src/components/components/marker/DraggableMarkerExample.astro b/docs/src/components/components/marker/DraggableMarkerExample.astro new file mode 100644 index 00000000..54dde7ee --- /dev/null +++ b/docs/src/components/components/marker/DraggableMarkerExample.astro @@ -0,0 +1,37 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `@Composable +fun DraggableMarkerExample() { + var markerPosition by remember { + mutableStateOf(GeoPoint.fromLatLong(37.7749, -122.4194)) + } + + // ${commentForMapViewUsage} + MapView( + state = mapViewState + ) { + Marker( + position = markerPosition, + draggable = true, + icon = DefaultIcon( + label = "Drag me", + fillColor = Color.Green + ), + onDrag = { markerState -> + markerPosition = markerState.position + } + ) + } +}`; +--- + + diff --git a/docs/src/components/components/marker/DraggableMarkerWithStateExample.astro b/docs/src/components/components/marker/DraggableMarkerWithStateExample.astro new file mode 100644 index 00000000..a2c45f55 --- /dev/null +++ b/docs/src/components/components/marker/DraggableMarkerWithStateExample.astro @@ -0,0 +1,35 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "MapViewには GoogleMapView や MapboxMapView など、利用する地図SDKのコンポーネントを指定します" +} = Astro.props; + +const code = `@Composable +fun DraggableMarkerExample() { + val markerState = MarkerState( + position = GeoPoint.fromLatLong(37.7749, -122.4194), + draggable = true, + icon = DefaultIcon( + label = "Drag me", + fillColor = Color.Green + ), + onDrag = { markerState -> + println("position: ${'${'}GeoPoint.from(markerState.position).toUrlValue(6)}") + } + ) + + // ${commentForMapViewUsage} + MapView( + state = mapViewState + ) { + Marker(markerState) + } +}`; +--- + + diff --git a/docs/src/components/components/marker/DrawableDefaultIconSignature.astro b/docs/src/components/components/marker/DrawableDefaultIconSignature.astro new file mode 100644 index 00000000..e41b1949 --- /dev/null +++ b/docs/src/components/components/marker/DrawableDefaultIconSignature.astro @@ -0,0 +1,13 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `DrawableDefaultIcon( + backgroundDrawable: Drawable, + scale: Float = 1.0f, + strokeColor: Color? = null, + strokeWidth: Dp = 1.dp +)`; +--- + + + diff --git a/docs/src/components/components/marker/ImageIconSignature.astro b/docs/src/components/components/marker/ImageIconSignature.astro new file mode 100644 index 00000000..7e67e8f1 --- /dev/null +++ b/docs/src/components/components/marker/ImageIconSignature.astro @@ -0,0 +1,12 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `ImageIcon( + drawable: Drawable, + anchor: Offset = Offset(0.5f, 0.5f), + debug: Boolean = false +)`; +--- + + + diff --git a/docs/src/components/components/marker/MarkerAnimation.astro b/docs/src/components/components/marker/MarkerAnimation.astro new file mode 100644 index 00000000..f21ed46b --- /dev/null +++ b/docs/src/components/components/marker/MarkerAnimation.astro @@ -0,0 +1,15 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + dropText: string; + bounceText: string; +} + +const { dropText, bounceText } = Astro.props; +--- + +
    +
  • Drop - {dropText}
  • +
  • Bounce - {bounceText}
  • +
diff --git a/docs/src/components/components/marker/MarkerBasicSignature.astro b/docs/src/components/components/marker/MarkerBasicSignature.astro new file mode 100644 index 00000000..902a0c33 --- /dev/null +++ b/docs/src/components/components/marker/MarkerBasicSignature.astro @@ -0,0 +1,22 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `@Composable +fun MapViewScope.Marker( + position: GeoPointInterface, + clickable: Boolean = true, + draggable: Boolean = false, + icon: MarkerIconInterface? = null, + extra: Serializable? = null, + id: String? = null, + onClick: OnMarkerEventHandler? = null, + onDragStart: OnMarkerEventHandler? = null, + onDrag: OnMarkerEventHandler? = null, + onDragEnd: OnMarkerEventHandler? = null, + onAnimateStart: OnMarkerEventHandler? = null, + onAnimateEnd: OnMarkerEventHandler? = null, +)`; +--- + + + diff --git a/docs/src/components/components/marker/MarkerStateSignature.astro b/docs/src/components/components/marker/MarkerStateSignature.astro new file mode 100644 index 00000000..c3cb2309 --- /dev/null +++ b/docs/src/components/components/marker/MarkerStateSignature.astro @@ -0,0 +1,9 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `@Composable +fun MapViewScope.Marker(state: MarkerState)`; +--- + + + diff --git a/docs/src/components/components/marker/MultipleMarkersExample.astro b/docs/src/components/components/marker/MultipleMarkersExample.astro new file mode 100644 index 00000000..b115b9cc --- /dev/null +++ b/docs/src/components/components/marker/MultipleMarkersExample.astro @@ -0,0 +1,56 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `// ${commentForMapViewUsage} +MapView(state = mapViewState) { + // Default icon with different scales + Marker( + position = GeoPoint.fromLatLong(37.7749, -122.4194), + icon = DefaultIcon(scale = 0.7f, label = "Small") + ) + + Marker( + position = GeoPoint.fromLatLong(37.7849, -122.4094), + icon = DefaultIcon(scale = 1.0f, label = "Normal") + ) + + Marker( + position = GeoPoint.fromLatLong(37.7949, -122.3994), + icon = DefaultIcon(scale = 1.4f, label = "Large") + ) + + // Custom colored marker + Marker( + position = GeoPoint.fromLatLong(37.7649, -122.4294), + icon = DefaultIcon( + fillColor = Color.Yellow, + strokeColor = Color.Black, + strokeWidth = 2.dp, + label = "Custom" + ) + ) + + // Drawable icon marker + val context = LocalContext.current + AppCompatResources.getDrawable(context, R.drawable.custom_icon)?.let { drawable -> + Marker( + position = GeoPoint.fromLatLong(37.7549, -122.4394), + icon = DrawableDefaultIcon( + backgroundDrawable = drawable, + scale = 1.2f + ) + ) + } +}`; +--- + + + diff --git a/docs/src/components/components/polygon/BasicPolygonExample.astro b/docs/src/components/components/polygon/BasicPolygonExample.astro new file mode 100644 index 00000000..9ad3fe19 --- /dev/null +++ b/docs/src/components/components/polygon/BasicPolygonExample.astro @@ -0,0 +1,42 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewReplacement?: string; + firstLatitude?: number; + firstLongitude?: number; + secondLatitude?: number; + secondLongitude?: number; + thirdLatitude?: number; + thirdLongitude?: number; +} + +const { + commentForMapViewReplacement = 'Replace MapView with your chosen provider, such as GoogleMapView or MapboxMapView', + firstLatitude = 37.7749, + firstLongitude = -122.4194, + secondLatitude = 37.7849, + secondLongitude = -122.4094, + thirdLatitude = 37.7749, + thirdLongitude = -122.3994, +} = Astro.props; + +const code = `// ${commentForMapViewReplacement} +MapLibreMapView(state = mapViewState) { + val trianglePoints = listOf( + GeoPoint.fromLatLong(${firstLatitude}, ${firstLongitude}), + GeoPoint.fromLatLong(${secondLatitude}, ${secondLongitude}), + GeoPoint.fromLatLong(${thirdLatitude}, ${thirdLongitude}), + GeoPoint.fromLatLong(${firstLatitude}, ${firstLongitude}) + ) + + Polygon( + points = trianglePoints, + strokeColor = Color.Blue, + strokeWidth = 2.dp, + fillColor = Color.Blue.copy(alpha = 0.3f) + ) +}`; +--- + + diff --git a/docs/src/components/components/polygon/ComplexPolygonExample.astro b/docs/src/components/components/polygon/ComplexPolygonExample.astro new file mode 100644 index 00000000..d54f75c0 --- /dev/null +++ b/docs/src/components/components/polygon/ComplexPolygonExample.astro @@ -0,0 +1,65 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForStarPolygon?: string; + centerLatitude?: number; + centerLongitude?: number; + outerRadius?: number; + innerRadius?: number; + extraLabel?: string; + markerLabel?: string; +} + +const { + commentForStarPolygon = 'Star-shaped polygon', + centerLatitude = 37.7749, + centerLongitude = -122.4194, + outerRadius = 0.01, + innerRadius = 0.005, + extraLabel = 'Star polygon', + markerLabel = '⭐', +} = Astro.props; + +const code = `@Composable +fun ComplexPolygonExample() { + // ${commentForStarPolygon} + val starPoints = remember { + val centerLat = ${centerLatitude} + val centerLng = ${centerLongitude} + val outerRadius = ${outerRadius} + val innerRadius = ${innerRadius} + + buildList { + for (i in 0 until 10) { + val angle = (i * 36.0) * Math.PI / 180.0 + val radiusMeters = if (i % 2 == 0) outerRadius else innerRadius + val lat = centerLat + radiusMeters * cos(angle) + val lng = centerLng + radiusMeters * sin(angle) + add(GeoPoint.fromLatLong(lat, lng)) + } + add(first()) + } + } + + MapView(state = mapViewState) { + Polygon( + points = starPoints, + strokeColor = Color.Magenta, + strokeWidth = 2.dp, + fillColor = Color.Magenta.copy(alpha = 0.3f), + extra = "${extraLabel}" + ) + + Marker( + position = GeoPoint.fromLatLong(${centerLatitude}, ${centerLongitude}), + icon = DefaultIcon( + fillColor = Color.Magenta, + label = "${markerLabel}" + ) + ) + } +}`; +--- + + diff --git a/docs/src/components/components/polygon/DynamicPolygonExample.astro b/docs/src/components/components/polygon/DynamicPolygonExample.astro new file mode 100644 index 00000000..3ce8cedc --- /dev/null +++ b/docs/src/components/components/polygon/DynamicPolygonExample.astro @@ -0,0 +1,66 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `@Composable +fun DynamicPolygonExample() { + var polygonPoints by remember { mutableStateOf>(emptyList()) } + var isCreating by remember { mutableStateOf(false) } + + Column { + Row { + Button( + onClick = { + isCreating = !isCreating + if (!isCreating && polygonPoints.isNotEmpty()) { + polygonPoints = polygonPoints + polygonPoints.first() + } + } + ) { + Text(if (isCreating) "Finish Polygon" else "Create Polygon") + } + + Button(onClick = { polygonPoints = emptyList() }) { + Text("Clear") + } + } + + Text("Points: \${polygonPoints.size}") + + MapView( + state = mapViewState, + onMapClick = { geoPoint -> + if (isCreating) { + polygonPoints = polygonPoints + geoPoint + } + } + ) { + if (polygonPoints.size >= 3) { + Polygon( + points = polygonPoints, + strokeColor = Color.Purple, + strokeWidth = 2.dp, + fillColor = if (isCreating) + Color.Purple.copy(alpha = 0.1f) + else + Color.Purple.copy(alpha = 0.3f) + ) + } + + polygonPoints.forEachIndexed { index, point -> + Marker( + position = point, + icon = DefaultIcon( + fillColor = if (index == 0) Color.Green + else if (index == polygonPoints.size - 1 && !isCreating) Color.Red + else Color.Blue, + label = "\${index + 1}", + scale = 0.7f + ) + ) + } + } + } +}`; +--- + + diff --git a/docs/src/components/components/polygon/GeodesicPolygonComparisonExample.astro b/docs/src/components/components/polygon/GeodesicPolygonComparisonExample.astro new file mode 100644 index 00000000..e3384ab7 --- /dev/null +++ b/docs/src/components/components/polygon/GeodesicPolygonComparisonExample.astro @@ -0,0 +1,144 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + centerLatitude?: number; + centerLongitude?: number; + zoomLevel?: number; + point1Longitude?: number; + point1Latitude?: number; + point2Longitude?: number; + point2Latitude?: number; + point3Longitude?: number; + point3Latitude?: number; + point4Longitude?: number; + point4Latitude?: number; + mapLoadedMessage?: string; + commentForMapClickClear?: string; + markerDragStartMessagePrefix?: string; + markerDragMessagePrefix?: string; + markerDragEndMessagePrefix?: string; + commentForInteractiveMarkers?: string; + commentForSelectedMarkerInfo?: string; +} + +const { + centerLatitude = 30.0, + centerLongitude = 0.0, + zoomLevel = 2.0, + point1Longitude = 23.66, + point1Latitude = 56.42, + point2Longitude = 13.39, + point2Latitude = 2.95, + point3Longitude = -87.82, + point3Latitude = 38.58, + point4Longitude = 23.66, + point4Latitude = 56.42, + mapLoadedMessage = 'Map loaded and ready', + commentForMapClickClear = 'Clear selection when the map is clicked', + markerDragStartMessagePrefix = 'Started dragging marker', + markerDragMessagePrefix = 'Dragging marker to', + markerDragEndMessagePrefix = 'Finished dragging marker', + commentForInteractiveMarkers = 'Interactive content with markers', + commentForSelectedMarkerInfo = 'Draw the selected marker', +} = Astro.props; + +const code = `@Composable +fun MapView(modifier: Modifier = Modifier) { + val mapViewState = + rememberArcGISMapViewState( + cameraPosition = + MapCameraPosition( + position = GeoPoint(${centerLatitude}, ${centerLongitude}), + zoom = ${zoomLevel}, + ), + ) + + val points = + listOf( + GeoPoint.fromLongLat(${point1Longitude}, ${point1Latitude}), + GeoPoint.fromLongLat(${point2Longitude}, ${point2Latitude}), + GeoPoint.fromLongLat(${point3Longitude}, ${point3Latitude}), + GeoPoint.fromLongLat(${point4Longitude}, ${point4Latitude}), + ) + + var marker by remember { mutableStateOf(null) } + val onMarkerClick: OnMarkerEventHandler = { markerState -> + marker = markerState + } + val onMarkerDragStart: OnMarkerEventHandler = { markerState -> + println("${markerDragStartMessagePrefix}: ${'$'}{markerState.id}") + } + val onMarkerDrag: OnMarkerEventHandler = { markerState -> + println("${markerDragMessagePrefix}: ${'$'}{markerState.position}") + } + val onMarkerDragEnd: OnMarkerEventHandler = { markerState -> + println("${markerDragEndMessagePrefix}: ${'$'}{markerState.id}") + } + val onPolygonClick: OnPolygonEventHandler = { event -> + marker = MarkerState( + position = event.clicked, + icon = DefaultIcon( + fillColor = event.state.fillColor, + strokeColor = Color.Red, + ), + animation = MarkerAnimation.Drop, + draggable = true, + onClick = onMarkerClick, + onDragStart = onMarkerDragStart, + onDrag = onMarkerDrag, + onDragEnd = onMarkerDragEnd, + ) + } + + val polygonState = + remember { + PolygonState( + points = points, + strokeColor = Color.Yellow.copy(alpha = 0.3f), + strokeWidth = 3.dp, + fillColor = Color.Green.copy(alpha = 0.5f), + geodesic = false, + zIndex = 0, + onClick = onPolygonClick, + ) + } + + val geodesicPolygonState = + remember { + PolygonState( + points = points, + strokeColor = Color.Red.copy(alpha = 0.3f), + strokeWidth = 3.dp, + fillColor = Color.Blue.copy(alpha = 0.5f), + geodesic = true, + zIndex = 1, + onClick = onPolygonClick, + ) + } + + ArcGISMapView( + modifier = modifier, + state = mapViewState, + onMapLoaded = { + println("${mapLoadedMessage}") + }, + onMapClick = { + marker = null // ${commentForMapClickClear} + } + ) { + + // ${commentForInteractiveMarkers} + Polygon(polygonState) + Polygon(geodesicPolygonState) + + // ${commentForSelectedMarkerInfo} + marker?.let { markerState -> + Marker(markerState) + } + } +} +`; +--- + + diff --git a/docs/src/components/components/polygon/InteractivePolygonExample.astro b/docs/src/components/components/polygon/InteractivePolygonExample.astro new file mode 100644 index 00000000..c7c72d02 --- /dev/null +++ b/docs/src/components/components/polygon/InteractivePolygonExample.astro @@ -0,0 +1,87 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + vertexPrefix?: string; + polygonClickedLog?: string; +} + +const { + vertexPrefix = "Vertex ", + polygonClickedLog = "Polygon clicked at: ${polygonEvent.clicked}", +} = Astro.props; + +const code = `@Composable +fun InteractivePolygonExample() { + val mapViewState = + rememberMapLibreMapViewState( + cameraPosition = + MapCameraPosition( + position = GeoPoint.fromLatLong(37.7809, -122.4094), + zoom = 13.5, + ), + ) + + var vertices by remember { + mutableStateOf( + listOf( + GeoPoint.fromLatLong(37.7749, -122.4194), + GeoPoint.fromLatLong(37.7849, -122.4094), + GeoPoint.fromLatLong(37.7799, -122.3994), + GeoPoint.fromLatLong(37.7649, -122.4094) + ) + ) + } + + val closedVertices = vertices + vertices.first() + + val polygonState = PolygonState( + id = "polygon", // important + points = closedVertices, + strokeColor = Color.Red, + strokeWidth = 3.dp, + fillColor = Color.Red.copy(alpha = 0.2f), + onClick = { polygonEvent -> + println("${polygonClickedLog} at: \${polygonEvent.clicked}") + } + ) + + val onVertexDrag: (MarkerState) -> Unit = { markerState -> + val vertexIndex = markerState.extra as Int + vertices = vertices.toMutableList().apply { + if (vertexIndex < size) { + set(vertexIndex, GeoPoint.from(markerState.position)) + } + } + } + + val vertexMarkers = vertices.mapIndexed { index, point -> + MarkerState( + id = "marker-\${index + 1}", // important + position = point, + icon = DefaultIcon( + fillColor = Color.Red, + strokeColor = Color.White, + label = "\${index + 1}", + scale = 0.8f + ), + draggable = true, + extra = index, + onDrag = onVertexDrag, + ) + } + + MapLibreMapView( + modifier = modifier, + state = mapViewState + ) { + Polygon(polygonState) + vertexMarkers.forEach { marker -> + Marker(marker) + } + } +} +`; +--- + + diff --git a/docs/src/components/components/polygon/MultiplePolygonsExample.astro b/docs/src/components/components/polygon/MultiplePolygonsExample.astro new file mode 100644 index 00000000..d2717545 --- /dev/null +++ b/docs/src/components/components/polygon/MultiplePolygonsExample.astro @@ -0,0 +1,64 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewReplacement?: string; + blueZoneExtra?: string; + redBoundaryExtra?: string; + greenAreaExtra?: string; +} + +const { + commentForMapViewReplacement = 'Replace MapView with your chosen provider, such as GoogleMapView or MapboxMapView', + blueZoneExtra = 'Blue zone', + redBoundaryExtra = 'Red boundary', + greenAreaExtra = 'Green area', +} = Astro.props; + +const code = `// ${commentForMapViewReplacement} +MapView(state = mapViewState) { + Polygon( + points = listOf( + GeoPoint.fromLatLong(37.7749, -122.4194), + GeoPoint.fromLatLong(37.7849, -122.4194), + GeoPoint.fromLatLong(37.7849, -122.4094), + GeoPoint.fromLatLong(37.7749, -122.4094), + GeoPoint.fromLatLong(37.7749, -122.4194) + ), + strokeColor = Color.Blue, + strokeWidth = 2.dp, + fillColor = Color.Blue.copy(alpha = 0.4f), + extra = "${blueZoneExtra}" + ) + + Polygon( + points = listOf( + GeoPoint.fromLatLong(37.7649, -122.4194), + GeoPoint.fromLatLong(37.7749, -122.4194), + GeoPoint.fromLatLong(37.7749, -122.4094), + GeoPoint.fromLatLong(37.7649, -122.4094), + GeoPoint.fromLatLong(37.7649, -122.4194) + ), + strokeColor = Color.Red, + strokeWidth = 3.dp, + fillColor = Color.Transparent, + extra = "${redBoundaryExtra}" + ) + + Polygon( + points = listOf( + GeoPoint.fromLatLong(37.7549, -122.4194), + GeoPoint.fromLatLong(37.7649, -122.4194), + GeoPoint.fromLatLong(37.7649, -122.4094), + GeoPoint.fromLatLong(37.7549, -122.4094), + GeoPoint.fromLatLong(37.7549, -122.4194) + ), + strokeColor = Color.Green, + strokeWidth = 1.dp, + fillColor = Color.Green.copy(alpha = 0.2f), + extra = "${greenAreaExtra}" + ) +}`; +--- + + diff --git a/docs/src/components/components/polygon/PolygonBasicSignature.astro b/docs/src/components/components/polygon/PolygonBasicSignature.astro new file mode 100644 index 00000000..8432386c --- /dev/null +++ b/docs/src/components/components/polygon/PolygonBasicSignature.astro @@ -0,0 +1,17 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `@Composable +fun Polygon( + points: List, + id: String? = null, + strokeColor: Color = Color.Black, + strokeWidth: Dp = 1.dp, + fillColor: Color = Color.Transparent, + geodesic: Boolean = false, + extra: Serializable? = null +)`; +--- + + + diff --git a/docs/src/components/components/polygon/PolygonEventHandlingExample.astro b/docs/src/components/components/polygon/PolygonEventHandlingExample.astro new file mode 100644 index 00000000..93b4b7f1 --- /dev/null +++ b/docs/src/components/components/polygon/PolygonEventHandlingExample.astro @@ -0,0 +1,49 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewReplacement?: string; + logPolygonClicked?: string; + logVerticesLabel?: string; + logClickLocationLabel?: string; + logExtraDataLabel?: string; + logApproxAreaLabel?: string; + extraLabel?: string; +} + +const { + commentForMapViewReplacement = 'Replace MapView with your chosen provider, such as GoogleMapView or MapboxMapView', + logPolygonClicked = 'Polygon clicked:', + logVerticesLabel = ' Vertices: ${polygon.points.size}', + logClickLocationLabel = ' Click location: ${clickPoint}', + logExtraDataLabel = ' Extra data: ${polygon.extra}', + logApproxAreaLabel = ' Approximate area: $area sq meters', + extraLabel = 'Interactive polygon', +} = Astro.props; + +const code = `// ${commentForMapViewReplacement} +MapView( + state = mapViewState +) { + Polygon( + points = polygonPoints, + strokeColor = Color.Green, + fillColor = Color.Green.copy(alpha = 0.3f), + extra = "${extraLabel}", + onClick = { polygonEvent -> + val polygon = polygonEvent.state + val clickPoint = polygonEvent.clicked + + println("${logPolygonClicked}") + println("${logVerticesLabel}") + println("${logClickLocationLabel}") + println("${logExtraDataLabel}") + + val area = calculatePolygonArea(polygon.points) + println("${logApproxAreaLabel}") + } + ) +}`; +--- + + diff --git a/docs/src/components/components/polygon/PolygonFillStyleExamples.astro b/docs/src/components/components/polygon/PolygonFillStyleExamples.astro new file mode 100644 index 00000000..d1b965cb --- /dev/null +++ b/docs/src/components/components/polygon/PolygonFillStyleExamples.astro @@ -0,0 +1,42 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForSolidFill?: string; + commentForSemiTransparentFill?: string; + commentForNoFill?: string; + commentForGradientEffect?: string; +} + +const { + commentForSolidFill = 'Solid fill', + commentForSemiTransparentFill = 'Semi-transparent fill', + commentForNoFill = 'No fill (outline only)', + commentForGradientEffect = 'Gradient-like effect using multiple polygons', +} = Astro.props; + +const code = `// ${commentForSolidFill} +Polygon( + points = points, + fillColor = Color.Red +) + +// ${commentForSemiTransparentFill} +Polygon( + points = points, + fillColor = Color.Red.copy(alpha = 0.5f) +) + +// ${commentForNoFill} +Polygon( + points = points, + fillColor = Color.Transparent +) + +// ${commentForGradientEffect} +Polygon(points = points, fillColor = Color.Blue.copy(alpha = 0.1f)) +Polygon(points = smallerPoints, fillColor = Color.Blue.copy(alpha = 0.2f))`; +--- + + + diff --git a/docs/src/components/components/polygon/PolygonStateSignature.astro b/docs/src/components/components/polygon/PolygonStateSignature.astro new file mode 100644 index 00000000..9c61e054 --- /dev/null +++ b/docs/src/components/components/polygon/PolygonStateSignature.astro @@ -0,0 +1,19 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `PolygonState( + points: List, + id: String? = null, + strokeColor: Color = Color.Black, + strokeWidth: Dp = 1.dp, + fillColor: Color = Color.Transparent, + geodesic: Boolean = false, + extra: Serializable? = null +) + +@Composable +fun Polygon(state: PolygonState)`; +--- + + + diff --git a/docs/src/components/components/polygon/PolygonStrokeStyleExamples.astro b/docs/src/components/components/polygon/PolygonStrokeStyleExamples.astro new file mode 100644 index 00000000..31c2db07 --- /dev/null +++ b/docs/src/components/components/polygon/PolygonStrokeStyleExamples.astro @@ -0,0 +1,39 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForThinBorder?: string; + commentForThickBorder?: string; + commentForNoBorder?: string; +} + +const { + commentForThinBorder = 'Thin border', + commentForThickBorder = 'Thick border', + commentForNoBorder = 'No border', +} = Astro.props; + +const code = `// ${commentForThinBorder} +Polygon( + points = points, + strokeColor = Color.Black, + strokeWidth = 1.dp +) + +// ${commentForThickBorder} +Polygon( + points = points, + strokeColor = Color.Black, + strokeWidth = 5.dp +) + +// ${commentForNoBorder} +Polygon( + points = points, + strokeColor = Color.Transparent, + strokeWidth = 0.dp +)`; +--- + + + diff --git a/docs/src/components/components/polyline/BasicPolylineExample.astro b/docs/src/components/components/polyline/BasicPolylineExample.astro new file mode 100644 index 00000000..b7418251 --- /dev/null +++ b/docs/src/components/components/polyline/BasicPolylineExample.astro @@ -0,0 +1,58 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + centerLat?: number; + centerLng?: number; + zoom?: number; + commentForMapViewUsage?: string; +} + +const { + centerLat = 53.566853, + centerLng = 9.988269, + zoom = 14.0, + commentForMapViewUsage = "Replace MapboxMapView with GoogleMapView, HereMapView, etc" +} = Astro.props; + +const code = `@Composable +fun BasicPolylineExample(modifier: Modifier = Modifier) { + val center = GeoPoint.fromLatLong(${centerLat}, ${centerLng}) + + // 地図の作成 + val camera = + MapCameraPosition( + position = center, + zoom = ${zoom}, + ) + val mapViewState = + rememberMapboxMapViewState( + cameraPosition = camera, + ) + val routePoints = listOf( + GeoPoint.fromLatLong(53.561011,9.989448), + GeoPoint.fromLatLong(53.563203,9.985800), + GeoPoint.fromLatLong(53.564579,9.983525), + GeoPoint.fromLatLong(53.566873,9.980822), + GeoPoint.fromLatLong(53.567943,9.982152), + GeoPoint.fromLatLong(53.570186,9.984813), + GeoPoint.fromLatLong(53.572683,9.986143), + GeoPoint.fromLatLong(53.572658,9.988675), + GeoPoint.fromLatLong(53.572709,9.990392) + ) + + // ${commentForMapViewUsage} + MapboxMapView( + state = mapViewState, + modifier = modifier, + ) { + Polyline( + points = routePoints, + strokeColor = Color.Blue, + strokeWidth = 9.dp + ) + } +}`; +--- + + diff --git a/docs/src/components/components/polyline/DynamicPolylineExample.astro b/docs/src/components/components/polyline/DynamicPolylineExample.astro new file mode 100644 index 00000000..b9d3553a --- /dev/null +++ b/docs/src/components/components/polyline/DynamicPolylineExample.astro @@ -0,0 +1,58 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `@Composable +fun DynamicPolylineExample() { + val center = GeoPoint.fromLatLong(53.566853, 9.988269) + + val camera = MapCameraPosition(position = center, zoom = 14.0) + val mapViewState = rememberMapLibreMapViewState(cameraPosition = camera) + + var points by remember { mutableStateOf>(emptyList()) } + var isDrawing by remember { mutableStateOf(false) } + + Column(modifier = modifier) { + Row { + Button(onClick = { isDrawing = !isDrawing }) { + Text(if (isDrawing) "Stop Drawing" else "Start Drawing") + } + Button(onClick = { points = emptyList() }) { + Text("Clear") + } + } + + MapLibreMapView( + state = mapViewState, + onMapClick = { geoPoint -> + if (isDrawing) { + points = points + geoPoint + } + } + ) { + if (points.isNotEmpty()) { + Polyline( + points = points, + strokeColor = Color.Red, + strokeWidth = 3.dp + ) + + points.forEachIndexed { index, point -> + Marker( + position = point, + icon = DefaultIcon( + fillColor = if (index == 0) Color.Green + else if (index == points.size - 1) Color.Red + else Color.Blue, + label = "\${index + 1}", + scale = 0.8f + ) + ) + } + } + } + } +}`; +--- + + + diff --git a/docs/src/components/components/polyline/GeodesicPolylineExample.astro b/docs/src/components/components/polyline/GeodesicPolylineExample.astro new file mode 100644 index 00000000..4cbbc398 --- /dev/null +++ b/docs/src/components/components/polyline/GeodesicPolylineExample.astro @@ -0,0 +1,56 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `@Composable +fun GeodesicPolylineExample(modifier: Modifier = Modifier) { + val center = GeoPoint.fromLatLong(36.0, -160.0) + val camera = MapCameraPosition(position = center, zoom = 4.0) + val mapViewState = rememberMapboxMapViewState(cameraPosition = camera) + + var markers by remember { mutableStateOf>(emptyList()) } + val onPolylineClick: OnPolylineEventHandler = { polylineEvent -> + markers = markers + MarkerState( + icon = DefaultIcon(fillColor = polylineEvent.state.strokeColor), + position = polylineEvent.clicked + ) + } + + MapboxMapView( + state = mapViewState, + modifier = modifier + ) { + val longDistancePoints = listOf( + GeoPoint.fromLatLong(35.548852, 139.784086), // 羽田空港 + GeoPoint.fromLatLong(37.615223, -122.389979) // サンフランシスコ空港 + ) + + // 標準線 + Polyline( + id = "straight-line", + points = longDistancePoints, + strokeColor = Color.Red, + strokeWidth = 3.dp, + geodesic = false, + extra = "Straight line", + onClick = onPolylineClick + ) + + // 測地線 + Polyline( + id = "geodesic-line", + points = longDistancePoints, + strokeColor = Color.Blue, + strokeWidth = 3.dp, + geodesic = true, + extra = "Geodesic line", + onClick = onPolylineClick + ) + + markers.forEach { markerState -> + Marker(markerState) + } + } +}`; +--- + + diff --git a/docs/src/components/components/polyline/InteractivePolylineExample.astro b/docs/src/components/components/polyline/InteractivePolylineExample.astro new file mode 100644 index 00000000..0a6c23a4 --- /dev/null +++ b/docs/src/components/components/polyline/InteractivePolylineExample.astro @@ -0,0 +1,67 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `@Composable +fun InteractivePolylineExample() { + val center = GeoPoint.fromLatLong(53.566853, 9.988269) + + val camera = MapCameraPosition(position = center, zoom = 14.0) + val mapViewState = rememberMapboxMapViewState(cameraPosition = camera) + + var waypoints by remember { + mutableStateOf( + listOf( + GeoPoint.fromLatLong(53.561011, 9.989448), + GeoPoint.fromLatLong(53.563203, 9.985800), + GeoPoint.fromLatLong(53.564579, 9.983525), + GeoPoint.fromLatLong(53.566873, 9.980822), + GeoPoint.fromLatLong(53.567943, 9.982152), + GeoPoint.fromLatLong(53.570186, 9.984813), + GeoPoint.fromLatLong(53.572683, 9.986143), + GeoPoint.fromLatLong(53.572658, 9.988675), + GeoPoint.fromLatLong(53.572709, 9.990392) + ) + ) + } + + val polylineState = PolylineState( + points = waypoints, + strokeColor = Color.Blue, + strokeWidth = 4.dp, + geodesic = true + ) + + val onWaypointDrag: (MarkerState) -> Unit = { markerState -> + val markerIndex = markerState.extra as Int + markerIndex.let { index -> + waypoints = waypoints.toMutableList().apply { + if (index < size) { + set(index, markerState.position as GeoPoint) + } + } + } + } + + val waypointMarkers = waypoints.mapIndexed { index, point -> + MarkerState( + id = "marker-\${index}", + position = point, + icon = DefaultIcon(label = "\${index + 1}", scale = 0.7f), + draggable = true, + extra = index, + onDrag = onWaypointDrag + ) + } + + MapboxMapView( + state = mapViewState + ) { + Polyline(polylineState) + waypointMarkers.forEach { marker -> + Marker(marker) + } + } +}`; +--- + + diff --git a/docs/src/components/components/polyline/PolylineBasicSignature.astro b/docs/src/components/components/polyline/PolylineBasicSignature.astro new file mode 100644 index 00000000..d5984d94 --- /dev/null +++ b/docs/src/components/components/polyline/PolylineBasicSignature.astro @@ -0,0 +1,16 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `@Composable +fun Polyline( + points: List, + id: String? = null, + strokeColor: Color = Color.Black, + strokeWidth: Dp = 1.dp, + geodesic: Boolean = false, + extra: Serializable? = null +)`; +--- + + + diff --git a/docs/src/components/components/polyline/PolylineColorStyleExamples.astro b/docs/src/components/components/polyline/PolylineColorStyleExamples.astro new file mode 100644 index 00000000..fea281df --- /dev/null +++ b/docs/src/components/components/polyline/PolylineColorStyleExamples.astro @@ -0,0 +1,34 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForSolidColors?: string; + commentForSemiTransparent?: string; + commentForCustomColor?: string; + commentForMaterialGreen?: string; +} + +const { + commentForSolidColors = 'Solid colors', + commentForSemiTransparent = 'Semi-transparent', + commentForCustomColor = 'Custom color', + commentForMaterialGreen = 'Material green', +} = Astro.props; + +const code = `// ${commentForSolidColors} +Polyline(points = points, strokeColor = Color.Red) +Polyline(points = points, strokeColor = Color.Blue) +Polyline(points = points, strokeColor = Color.Green) + +// ${commentForSemiTransparent} +Polyline(points = points, strokeColor = Color.Red.copy(alpha = 0.7f)) + +// ${commentForCustomColor} +Polyline( + points = points, + strokeColor = Color(0xFF4CAF50) // ${commentForMaterialGreen} +)`; +--- + + + diff --git a/docs/src/components/components/polyline/PolylineEventHandlingExample.astro b/docs/src/components/components/polyline/PolylineEventHandlingExample.astro new file mode 100644 index 00000000..be25e7e2 --- /dev/null +++ b/docs/src/components/components/polyline/PolylineEventHandlingExample.astro @@ -0,0 +1,44 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; + polylineClickedLabel?: string; + pointsCountLabel?: string; + clickLocationLabel?: string; + extraDataLabel?: string; + extraValue?: string; +} + +const { + commentForMapViewUsage = 'Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView', + polylineClickedLabel = 'Polyline clicked:', + pointsCountLabel = 'Points count', + clickLocationLabel = 'Click location', + extraDataLabel = 'Extra data', + extraValue = 'Interactive route', +} = Astro.props; + +const code = `// ${commentForMapViewUsage} +MapView( + state = mapViewState +) { + Polyline( + points = routePoints, + strokeColor = Color.Blue, + strokeWidth = 4.dp, + extra = "${extraValue}", + onClick = { polylineEvent -> + val polyline = polylineEvent.state + val clickPoint = polylineEvent.clicked + + println("${polylineClickedLabel}") + println(" ${pointsCountLabel}: \${polyline.points.size}") + println(" ${clickLocationLabel}: \${clickPoint}") + println(" ${extraDataLabel}: \${polyline.extra}") + } + ) +}`; +--- + + diff --git a/docs/src/components/components/polyline/PolylineStateSignature.astro b/docs/src/components/components/polyline/PolylineStateSignature.astro new file mode 100644 index 00000000..b815f471 --- /dev/null +++ b/docs/src/components/components/polyline/PolylineStateSignature.astro @@ -0,0 +1,18 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `PolylineState( + points: List, + id: String? = null, + strokeColor: Color = Color.Black, + strokeWidth: Dp = 1.dp, + geodesic: Boolean = false, + extra: Serializable? = null +) + +@Composable +fun Polyline(state: PolylineState)`; +--- + + + diff --git a/docs/src/components/components/polyline/PolylineWidthStyleExamples.astro b/docs/src/components/components/polyline/PolylineWidthStyleExamples.astro new file mode 100644 index 00000000..f957effb --- /dev/null +++ b/docs/src/components/components/polyline/PolylineWidthStyleExamples.astro @@ -0,0 +1,36 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForThinLine?: string; + commentForMediumLine?: string; + commentForThickLine?: string; +} + +const { + commentForThinLine = 'Thin line', + commentForMediumLine = 'Medium line', + commentForThickLine = 'Thick line', +} = Astro.props; + +const code = `// ${commentForThinLine} +Polyline( + points = points, + strokeWidth = 1.dp +) + +// ${commentForMediumLine} +Polyline( + points = points, + strokeWidth = 3.dp +) + +// ${commentForThickLine} +Polyline( + points = points, + strokeWidth = 8.dp +)`; +--- + + + diff --git a/docs/src/components/core/geopoint/AltitudeExample.astro b/docs/src/components/core/geopoint/AltitudeExample.astro new file mode 100644 index 00000000..7ef621e4 --- /dev/null +++ b/docs/src/components/core/geopoint/AltitudeExample.astro @@ -0,0 +1,28 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForAltitude?: string; + altitudeComment?: string; + latitude?: number; + longitude?: number; + altitude?: number; +} + +const { + commentForAltitude = "Include altitude for 3D placement", + altitudeComment = "meters", + latitude = 27.9881, + longitude = 86.9250, + altitude = 8848.0 +} = Astro.props; + +const code = `// ${commentForAltitude} +val mountEverest = GeoPoint( + latitude = ${latitude}, + longitude = ${longitude}, + altitude = ${altitude} // ${altitudeComment} +)`; +--- + + diff --git a/docs/src/components/core/geopoint/BasicMarkerExample.astro b/docs/src/components/core/geopoint/BasicMarkerExample.astro new file mode 100644 index 00000000..ff4ee93e --- /dev/null +++ b/docs/src/components/core/geopoint/BasicMarkerExample.astro @@ -0,0 +1,32 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForPosition?: string; + commentForMapView?: string; + latitude?: number; + longitude?: number; + label?: string; +} + +const { + commentForPosition = "Basic marker placement", + commentForMapView = "Replace MapViewContainer with GoogleMapView, MapboxMapView, etc. for your chosen map SDK", + latitude = 37.7749, + longitude = -122.4194, + label = "SF" +} = Astro.props; + +const code = `// ${commentForPosition} +val sanFrancisco = GeoPoint.fromLatLong(${latitude}, ${longitude}) + +// ${commentForMapView} +MapViewContainer(state = mapViewState) { + Marker( + position = sanFrancisco, + icon = DefaultIcon(label = "${label}") + ) +}`; +--- + + diff --git a/docs/src/components/core/geopoint/EqualsExample.astro b/docs/src/components/core/geopoint/EqualsExample.astro new file mode 100644 index 00000000..223d7429 --- /dev/null +++ b/docs/src/components/core/geopoint/EqualsExample.astro @@ -0,0 +1,29 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForTolerance?: string; + latitude1?: number; + longitude1?: number; + altitude1?: number; + latitude2?: number; + longitude2?: number; + altitude2?: number; +} + +const { + commentForTolerance = "Within tolerance", + latitude1 = 37.7749, + longitude1 = -122.4194, + altitude1 = 100.0, + latitude2 = 37.77490001, + longitude2 = -122.41940001, + altitude2 = 100.00000001 +} = Astro.props; + +const code = `val point1 = GeoPoint(${latitude1}, ${longitude1}, ${altitude1}) +val point2 = GeoPoint(${latitude2}, ${longitude2}, ${altitude2}) +val isEqual = point1 == point2 // true(${commentForTolerance})`; +--- + + diff --git a/docs/src/components/core/geopoint/GeoPointFactoryMethods.astro b/docs/src/components/core/geopoint/GeoPointFactoryMethods.astro new file mode 100644 index 00000000..e80a4a5a --- /dev/null +++ b/docs/src/components/core/geopoint/GeoPointFactoryMethods.astro @@ -0,0 +1,37 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForFromLatLong?: string; + commentForFromLongLat?: string; + commentForFrom?: string; + commentForConstructor?: string; + latitude?: number; + longitude?: number; + altitude?: number; +} + +const { + commentForFromLatLong = "Standard creation - latitude first (common pattern)", + commentForFromLongLat = "Alternative - longitude first", + commentForFrom = "From existing GeoPointInterface", + commentForConstructor = "Direct constructor", + latitude = 37.7749, + longitude = -122.4194, + altitude = 100.0 +} = Astro.props; + +const code = `// ${commentForFromLatLong} +GeoPoint.fromLatLong(${latitude}, ${longitude}) + +// ${commentForFromLongLat} +GeoPoint.fromLongLat(${longitude}, ${latitude}) + +// ${commentForFrom} +GeoPoint.from(existingGeoPoint) + +// ${commentForConstructor} +GeoPoint(latitude = ${latitude}, longitude = ${longitude}, altitude = ${altitude})`; +--- + + diff --git a/docs/src/components/core/geopoint/GeoPointImpl.astro b/docs/src/components/core/geopoint/GeoPointImpl.astro new file mode 100644 index 00000000..1868d831 --- /dev/null +++ b/docs/src/components/core/geopoint/GeoPointImpl.astro @@ -0,0 +1,11 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `data class GeoPoint( + override val latitude: Double, + override val longitude: Double, + override val altitude: Double = 0.0 +) : GeoPointInterface`; +--- + + diff --git a/docs/src/components/core/geopoint/GeoPointInterface.astro b/docs/src/components/core/geopoint/GeoPointInterface.astro new file mode 100644 index 00000000..9cdfa0f9 --- /dev/null +++ b/docs/src/components/core/geopoint/GeoPointInterface.astro @@ -0,0 +1,11 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `interface GeoPointInterface { + val latitude: Double + val longitude: Double + val altitude: Double? +}`; +--- + + diff --git a/docs/src/components/core/geopoint/NormalizationExample.astro b/docs/src/components/core/geopoint/NormalizationExample.astro new file mode 100644 index 00000000..7804d3de --- /dev/null +++ b/docs/src/components/core/geopoint/NormalizationExample.astro @@ -0,0 +1,27 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForUsage?: string; + commentForInvalid?: string; + commentForValid?: string; + invalidLatitude?: number; + invalidLongitude?: number; +} + +const { + commentForUsage = "Usage example", + commentForInvalid = "Invalid coordinates", + commentForValid = "Clamped to valid range", + invalidLatitude = 100.0, + invalidLongitude = 200.0 +} = Astro.props; + +const code = `fun GeoPointInterface.normalize(): GeoPoint + +// ${commentForUsage} +val invalidPoint = GeoPoint.fromLatLong(${invalidLatitude}, ${invalidLongitude}) // ${commentForInvalid} +val validPoint = invalidPoint.normalize() // ${commentForValid}`; +--- + + diff --git a/docs/src/components/core/geopoint/ToUrlValueExample.astro b/docs/src/components/core/geopoint/ToUrlValueExample.astro new file mode 100644 index 00000000..d29388f7 --- /dev/null +++ b/docs/src/components/core/geopoint/ToUrlValueExample.astro @@ -0,0 +1,25 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForDefault?: string; + commentForCustom?: string; + latitude?: number; + longitude?: number; + precision?: number; +} + +const { + commentForDefault = "Default precision (6 digits)", + commentForCustom = "Custom precision (3 digits)", + latitude = 37.7749, + longitude = -122.4194, + precision = 3 +} = Astro.props; + +const code = `val point = GeoPoint(${latitude}, ${longitude}) +val urlValue = point.toUrlValue() // "${latitude.toFixed(6)},${longitude.toFixed(6)}" - ${commentForDefault} +val urlValue3 = point.toUrlValue(precision = ${precision}) // "${latitude.toFixed(precision)},${longitude.toFixed(precision)}" - ${commentForCustom}`; +--- + + diff --git a/docs/src/components/core/geopoint/ValidationExample.astro b/docs/src/components/core/geopoint/ValidationExample.astro new file mode 100644 index 00000000..918a14e8 --- /dev/null +++ b/docs/src/components/core/geopoint/ValidationExample.astro @@ -0,0 +1,25 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForUsage?: string; + commentForUse?: string; + latitude?: number; + longitude?: number; +} + +const { + commentForUsage = "Usage example", + commentForUse = "Use the point", + latitude = 37.7749, + longitude = -122.4194 +} = Astro.props; + +const code = `// ${commentForUsage} +val point = GeoPoint.fromLatLong(${latitude}, ${longitude}) +if (point.isValid()) { + // ${commentForUse} +}`; +--- + + diff --git a/docs/src/components/core/geopoint/WrapExample.astro b/docs/src/components/core/geopoint/WrapExample.astro new file mode 100644 index 00000000..3913c8a8 --- /dev/null +++ b/docs/src/components/core/geopoint/WrapExample.astro @@ -0,0 +1,23 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForExample?: string; + commentForOverflow?: string; + latitude?: number; + longitude?: number; +} + +const { + commentForExample = "Example: Coordinates beyond poles", + commentForOverflow = "Latitude exceeds 90 degrees", + latitude = 95.0, + longitude = 10.0 +} = Astro.props; + +const code = `// ${commentForExample} +val point = GeoPoint(${latitude}, ${longitude}) // ${commentForOverflow} +val wrapped = point.wrap() // 緯度: -85.0, 経度: 190.0 → -170.0`; +--- + + diff --git a/docs/src/components/core/georectbounds/BoundsBasedLoadingExample.astro b/docs/src/components/core/georectbounds/BoundsBasedLoadingExample.astro new file mode 100644 index 00000000..4fe8bc45 --- /dev/null +++ b/docs/src/components/core/georectbounds/BoundsBasedLoadingExample.astro @@ -0,0 +1,114 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForAllMarkersSimulation?: string; + baseLatitude?: number; + baseLongitude?: number; + latitudeStep?: number; + longitudeStep?: number; + viewportSouthWestLatitude?: number; + viewportSouthWestLongitude?: number; + viewportNorthEastLatitude?: number; + viewportNorthEastLongitude?: number; + commentForViewportSimulation?: string; + commentForMapViewUsage?: string; +} + +const { + commentForAllMarkersSimulation = "Simulate all available markers", + baseLatitude = 37.7, + baseLongitude = -122.5, + latitudeStep = 0.01, + longitudeStep = 0.01, + viewportSouthWestLatitude = 37.70, + viewportSouthWestLongitude = -122.50, + viewportNorthEastLatitude = 37.75, + viewportNorthEastLongitude = -122.45, + commentForViewportSimulation = "Simulate setting viewport bounds", + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `@Composable +fun BoundsBasedLoadingExample() { + var currentBounds by remember { mutableStateOf(null) } + var markersInBounds by remember { mutableStateOf>(emptyList()) } + + // ${commentForAllMarkersSimulation} + val allMarkers = remember { + List(100) { i -> + GeoPoint.fromLatLong( + ${baseLatitude} + (i % 10) * ${latitudeStep}, + ${baseLongitude} + (i / 10) * ${longitudeStep} + ) + } + } + + // Filter markers based on current bounds + LaunchedEffect(currentBounds) { + markersInBounds = currentBounds?.let { bounds -> + if (bounds.isEmpty) { + emptyList() + } else { + allMarkers.filter { marker -> + bounds.contains(marker) + } + } + } ?: emptyList() + } + + Column { + Text("Markers in bounds: ${'$'}{markersInBounds.size}/${'$'}{allMarkers.size}") + + Button( + onClick = { + // ${commentForViewportSimulation} + currentBounds = GeoRectBounds( + southWest = GeoPoint.fromLatLong(${viewportSouthWestLatitude}, ${viewportSouthWestLongitude}), + northEast = GeoPoint.fromLatLong(${viewportNorthEastLatitude}, ${viewportNorthEastLongitude}) + ) + } + ) { + Text("Set Viewport") + } + + // ${commentForMapViewUsage} + MapView(state = mapViewState) { + // Show only markers within bounds + markersInBounds.forEach { position -> + Marker( + position = position, + icon = DefaultIcon( + fillColor = Color.Green, + scale = 0.8f + ) + ) + } + + // Show current bounds + currentBounds?.let { bounds -> + if (!bounds.isEmpty) { + val sw = bounds.southWest!! + val ne = bounds.northEast!! + + Polygon( + points = listOf( + sw, + GeoPoint.fromLatLong(sw.latitude, ne.longitude), + ne, + GeoPoint.fromLatLong(ne.latitude, sw.longitude), + sw + ), + strokeColor = Color.Blue, + strokeWidth = 3.dp, + fillColor = Color.Blue.copy(alpha = 0.1f) + ) + } + } + } + } +}`; +--- + + + diff --git a/docs/src/components/core/georectbounds/BoundsEditorExample.astro b/docs/src/components/core/georectbounds/BoundsEditorExample.astro new file mode 100644 index 00000000..498c2bfd --- /dev/null +++ b/docs/src/components/core/georectbounds/BoundsEditorExample.astro @@ -0,0 +1,98 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + initialSouthWestLatitude?: number; + initialSouthWestLongitude?: number; + initialNorthEastLatitude?: number; + initialNorthEastLongitude?: number; + commentForMapViewUsage?: string; +} + +const { + initialSouthWestLatitude = 37.7649, + initialSouthWestLongitude = -122.4294, + initialNorthEastLatitude = 37.7849, + initialNorthEastLongitude = -122.4094, + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `@Composable +fun BoundsEditorExample() { + var bounds by remember { + mutableStateOf( + GeoRectBounds( + southWest = GeoPoint.fromLatLong(${initialSouthWestLatitude}, ${initialSouthWestLongitude}), + northEast = GeoPoint.fromLatLong(${initialNorthEastLatitude}, ${initialNorthEastLongitude}) + ) + ) + } + + val onCornerDrag: (MarkerState) -> Unit = { markerState -> + val newPosition = markerState.position + when (markerState.extra) { + "SW" -> { + bounds = GeoRectBounds( + southWest = newPosition as GeoPoint, + northEast = bounds.northEast + ) + } + "NE" -> { + bounds = GeoRectBounds( + southWest = bounds.southWest, + northEast = newPosition as GeoPoint + ) + } + } + } + + // ${commentForMapViewUsage} + MapView( + state = mapViewState + ) { + // Bounds visualization + if (!bounds.isEmpty) { + val sw = bounds.southWest!! + val ne = bounds.northEast!! + + // Bounds rectangle + Polygon( + points = listOf( + sw, + GeoPoint.fromLatLong(sw.latitude, ne.longitude), + ne, + GeoPoint.fromLatLong(ne.latitude, sw.longitude), + sw + ), + strokeColor = Color.Red, + fillColor = Color.Red.copy(alpha = 0.2f) + ) + + // Corner markers + Marker( + position = sw, + icon = DefaultIcon( + fillColor = Color.Green, + label = "SW" + ), + draggable = true, + extra = "SW", + onDrag = onCornerDrag + ) + + Marker( + position = ne, + icon = DefaultIcon( + fillColor = Color.Red, + label = "NE" + ), + draggable = true, + extra = "NE", + onDrag = onCornerDrag + ) + } + } +}`; +--- + + diff --git a/docs/src/components/core/georectbounds/BoundsToStringExample.astro b/docs/src/components/core/georectbounds/BoundsToStringExample.astro new file mode 100644 index 00000000..bd61e310 --- /dev/null +++ b/docs/src/components/core/georectbounds/BoundsToStringExample.astro @@ -0,0 +1,29 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + southWestLatitude?: number; + southWestLongitude?: number; + northEastLatitude?: number; + northEastLongitude?: number; +} + +const { + southWestLatitude = 37.7649, + southWestLongitude = -122.4294, + northEastLatitude = 37.7849, + northEastLongitude = -122.4094 +} = Astro.props; + +const code = `// For debugging +val bounds = GeoRectBounds( + southWest = GeoPoint.fromLatLong(${southWestLatitude}, ${southWestLongitude}), + northEast = GeoPoint.fromLatLong(${northEastLatitude}, ${northEastLongitude}) +) + +println(bounds.toString()) +// Output: ((${southWestLatitude}, ${southWestLongitude}), (${northEastLatitude}, ${northEastLongitude}))`; +--- + + + diff --git a/docs/src/components/core/georectbounds/ContainsPointExample.astro b/docs/src/components/core/georectbounds/ContainsPointExample.astro new file mode 100644 index 00000000..2bd21ad3 --- /dev/null +++ b/docs/src/components/core/georectbounds/ContainsPointExample.astro @@ -0,0 +1,39 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + boundsSouthWestLatitude?: number; + boundsSouthWestLongitude?: number; + boundsNorthEastLatitude?: number; + boundsNorthEastLongitude?: number; + testPointLatitude?: number; + testPointLongitude?: number; + commentForUsage?: string; +} + +const { + boundsSouthWestLatitude = 37.7649, + boundsSouthWestLongitude = -122.4294, + boundsNorthEastLatitude = 37.7849, + boundsNorthEastLongitude = -122.4094, + testPointLatitude = 37.7749, + testPointLongitude = -122.4194, + commentForUsage = "Point is inside bounds" +} = Astro.props; + +const code = `fun contains(point: GeoPointInterface): Boolean + +// Usage +val bounds = GeoRectBounds( + southWest = GeoPoint.fromLatLong(${boundsSouthWestLatitude}, ${boundsSouthWestLongitude}), + northEast = GeoPoint.fromLatLong(${boundsNorthEastLatitude}, ${boundsNorthEastLongitude}) +) + +val testPoint = GeoPoint.fromLatLong(${testPointLatitude}, ${testPointLongitude}) +val isInside = bounds.contains(testPoint) + +println("Point is inside bounds: $isInside")`; +--- + + + diff --git a/docs/src/components/core/georectbounds/DateLineCrossingExample.astro b/docs/src/components/core/georectbounds/DateLineCrossingExample.astro new file mode 100644 index 00000000..ef36109b --- /dev/null +++ b/docs/src/components/core/georectbounds/DateLineCrossingExample.astro @@ -0,0 +1,33 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + southWestLatitude?: number; + southWestLongitude?: number; + northEastLatitude?: number; + northEastLongitude?: number; + pointLatitude?: number; + pointLongitude?: number; +} + +const { + southWestLatitude = 20.0, + southWestLongitude = 170.0, + northEastLatitude = 40.0, + northEastLongitude = -170.0, + pointLatitude = 30.0, + pointLongitude = 175.0 +} = Astro.props; + +const code = `// Bounds crossing the date line +val pacificBounds = GeoRectBounds( + southWest = GeoPoint.fromLatLong(${southWestLatitude}, ${southWestLongitude}), // West of date line + northEast = GeoPoint.fromLatLong(${northEastLatitude}, ${northEastLongitude}) // East of date line +) + +val pointInPacific = GeoPoint.fromLatLong(${pointLatitude}, ${pointLongitude}) +val containsPoint = pacificBounds.contains(pointInPacific) // true`; +--- + + + diff --git a/docs/src/components/core/georectbounds/EmptyBoundsHandlingExample.astro b/docs/src/components/core/georectbounds/EmptyBoundsHandlingExample.astro new file mode 100644 index 00000000..6d2e75a9 --- /dev/null +++ b/docs/src/components/core/georectbounds/EmptyBoundsHandlingExample.astro @@ -0,0 +1,26 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + extendLatitude?: number; + extendLongitude?: number; +} + +const { + extendLatitude = 37.7749, + extendLongitude = -122.4194 +} = Astro.props; + +const code = `val emptyBounds = GeoRectBounds() + +println(emptyBounds.isEmpty) // true +println(emptyBounds.center) // null +println(emptyBounds.toSpan()) // null + +// Extending empty bounds +emptyBounds.extend(GeoPoint.fromLatLong(${extendLatitude}, ${extendLongitude})) +println(emptyBounds.isEmpty) // false`; +--- + + + diff --git a/docs/src/components/core/georectbounds/EqualsToExample.astro b/docs/src/components/core/georectbounds/EqualsToExample.astro new file mode 100644 index 00000000..de8be3f3 --- /dev/null +++ b/docs/src/components/core/georectbounds/EqualsToExample.astro @@ -0,0 +1,22 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForUsage?: string; +} + +const { + commentForUsage = "Usage" +} = Astro.props; + +const code = `fun equalsTo(other: GeoRectBounds): Boolean + +// ${commentForUsage} +val bounds1 = GeoRectBounds(/* ... */) +val bounds2 = GeoRectBounds(/* ... */) + +val areEqual = bounds1.equalsTo(bounds2)`; +--- + + + diff --git a/docs/src/components/core/georectbounds/ExtendBoundsExample.astro b/docs/src/components/core/georectbounds/ExtendBoundsExample.astro new file mode 100644 index 00000000..668577d9 --- /dev/null +++ b/docs/src/components/core/georectbounds/ExtendBoundsExample.astro @@ -0,0 +1,49 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForUsage?: string; + commentForStartEmpty?: string; + commentForBoundsGrow?: string; + commentForFinalBounds?: string; + firstPointLatitude?: number; + firstPointLongitude?: number; + secondPointLatitude?: number; + secondPointLongitude?: number; + thirdPointLatitude?: number; + thirdPointLongitude?: number; +} + +const { + commentForUsage = "Usage", + commentForStartEmpty = "Start empty", + commentForBoundsGrow = "Bounds grow to include each point", + commentForFinalBounds = "Final bounds", + firstPointLatitude = 37.7749, + firstPointLongitude = -122.4194, + secondPointLatitude = 37.7849, + secondPointLongitude = -122.4094, + thirdPointLatitude = 37.7649, + thirdPointLongitude = -122.4294 +} = Astro.props; + +const code = `fun extend(point: GeoPointInterface) + +// ${commentForUsage} +val bounds = GeoRectBounds() // ${commentForStartEmpty} + +val points = listOf( + GeoPoint.fromLatLong(${firstPointLatitude}, ${firstPointLongitude}), + GeoPoint.fromLatLong(${secondPointLatitude}, ${secondPointLongitude}), + GeoPoint.fromLatLong(${thirdPointLatitude}, ${thirdPointLongitude}) +) + +points.forEach { point -> + bounds.extend(point) // ${commentForBoundsGrow} +} + +println("${commentForFinalBounds}: $bounds")`; +--- + + + diff --git a/docs/src/components/core/georectbounds/GeoRectBoundsConstructor.astro b/docs/src/components/core/georectbounds/GeoRectBoundsConstructor.astro new file mode 100644 index 00000000..b341155b --- /dev/null +++ b/docs/src/components/core/georectbounds/GeoRectBoundsConstructor.astro @@ -0,0 +1,11 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `class GeoRectBounds( + southWest: GeoPoint? = null, + northEast: GeoPoint? = null +)`; +--- + + + diff --git a/docs/src/components/core/georectbounds/GeoRectBoundsCreationExample.astro b/docs/src/components/core/georectbounds/GeoRectBoundsCreationExample.astro new file mode 100644 index 00000000..72980818 --- /dev/null +++ b/docs/src/components/core/georectbounds/GeoRectBoundsCreationExample.astro @@ -0,0 +1,33 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForDefineArea?: string; + commentForEmptyBounds?: string; + southWestLatitude?: number; + southWestLongitude?: number; + northEastLatitude?: number; + northEastLongitude?: number; +} + +const { + commentForDefineArea = "Define a rectangular area", + commentForEmptyBounds = "Empty bounds (to be extended later)", + southWestLatitude = 37.7649, + southWestLongitude = -122.4294, + northEastLatitude = 37.7849, + northEastLongitude = -122.4094 +} = Astro.props; + +const code = `// ${commentForDefineArea} +val bounds = GeoRectBounds( + southWest = GeoPoint.fromLatLong(${southWestLatitude}, ${southWestLongitude}), + northeast = GeoPoint.fromLatLong(${northEastLatitude}, ${northEastLongitude}) +) + +// ${commentForEmptyBounds} +val bounds = GeoRectBounds()`; +--- + + + diff --git a/docs/src/components/core/georectbounds/GroundImageExample.astro b/docs/src/components/core/georectbounds/GroundImageExample.astro new file mode 100644 index 00000000..e17cea7e --- /dev/null +++ b/docs/src/components/core/georectbounds/GroundImageExample.astro @@ -0,0 +1,44 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; + southWestLatitude?: number; + southWestLongitude?: number; + northEastLatitude?: number; + northEastLongitude?: number; + overlayOpacity?: number; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView", + southWestLatitude = 37.7649, + southWestLongitude = -122.4294, + northEastLatitude = 37.7849, + northEastLongitude = -122.4094, + overlayOpacity = 0.7 +} = Astro.props; + +const code = `@Composable +fun GroundImageExample() { + val imageBounds = GeoRectBounds( + southWest = GeoPoint.fromLatLong(${southWestLatitude}, ${southWestLongitude}), + northEast = GeoPoint.fromLatLong(${northEastLatitude}, ${northEastLongitude}) + ) + + // ${commentForMapViewUsage} + MapView(state = mapViewState) { + val context = LocalContext.current + AppCompatResources.getDrawable(context, R.drawable.overlay_image)?.let { drawable -> + GroundImage( + bounds = imageBounds, + image = drawable, + opacity = ${overlayOpacity}f + ) + } + } +}`; +--- + + + diff --git a/docs/src/components/core/georectbounds/IntersectsBoundsExample.astro b/docs/src/components/core/georectbounds/IntersectsBoundsExample.astro new file mode 100644 index 00000000..c0fec080 --- /dev/null +++ b/docs/src/components/core/georectbounds/IntersectsBoundsExample.astro @@ -0,0 +1,23 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForUsage?: string; +} + +const { + commentForUsage = "Bounds intersect" +} = Astro.props; + +const code = `fun intersects(other: GeoRectBounds): Boolean + +// Usage +val bounds1 = GeoRectBounds(/* ... */) +val bounds2 = GeoRectBounds(/* ... */) + +val doIntersect = bounds1.intersects(bounds2) +println("Bounds intersect: $doIntersect")`; +--- + + + diff --git a/docs/src/components/core/georectbounds/ToUrlValueExample.astro b/docs/src/components/core/georectbounds/ToUrlValueExample.astro new file mode 100644 index 00000000..35f91149 --- /dev/null +++ b/docs/src/components/core/georectbounds/ToUrlValueExample.astro @@ -0,0 +1,22 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + defaultPrecision?: number; + highPrecision?: number; +} + +const { + defaultPrecision = 6, + highPrecision = 8 +} = Astro.props; + +const code = `fun toUrlValue(precision: Int = ${defaultPrecision}): String + +// Usage for API calls +val urlString = bounds.toUrlValue() // "37.764900,-122.429400,37.784900,-122.409400" +val preciseString = bounds.toUrlValue(precision = ${highPrecision})`; +--- + + + diff --git a/docs/src/components/core/georectbounds/UnionBoundsExample.astro b/docs/src/components/core/georectbounds/UnionBoundsExample.astro new file mode 100644 index 00000000..dab383fb --- /dev/null +++ b/docs/src/components/core/georectbounds/UnionBoundsExample.astro @@ -0,0 +1,42 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + firstSouthWestLatitude?: number; + firstSouthWestLongitude?: number; + firstNorthEastLatitude?: number; + firstNorthEastLongitude?: number; + secondSouthWestLatitude?: number; + secondSouthWestLongitude?: number; + secondNorthEastLatitude?: number; + secondNorthEastLongitude?: number; + commentForCombinedBounds?: string; +} + +const { + firstSouthWestLatitude = 37.7649, + firstSouthWestLongitude = -122.4294, + firstNorthEastLatitude = 37.7749, + firstNorthEastLongitude = -122.4194, + secondSouthWestLatitude = 37.7749, + secondSouthWestLongitude = -122.4194, + secondNorthEastLatitude = 37.7849, + secondNorthEastLongitude = -122.4094, + commentForCombinedBounds = "Contains both areas" +} = Astro.props; + +const code = `val bounds1 = GeoRectBounds( + southWest = GeoPoint.fromLatLong(${firstSouthWestLatitude}, ${firstSouthWestLongitude}), + northEast = GeoPoint.fromLatLong(${firstNorthEastLatitude}, ${firstNorthEastLongitude}) +) + +val bounds2 = GeoRectBounds( + southWest = GeoPoint.fromLatLong(${secondSouthWestLatitude}, ${secondSouthWestLongitude}), + northEast = GeoPoint.fromLatLong(${secondNorthEastLatitude}, ${secondNorthEastLongitude}) +) + +val combinedBounds = bounds1.union(bounds2) // ${commentForCombinedBounds}`; +--- + + + diff --git a/docs/src/components/core/georectbounds/ViewportBoundsExample.astro b/docs/src/components/core/georectbounds/ViewportBoundsExample.astro new file mode 100644 index 00000000..53ad9f74 --- /dev/null +++ b/docs/src/components/core/georectbounds/ViewportBoundsExample.astro @@ -0,0 +1,89 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMarkerSimulation?: string; + firstMarkerLatitude?: number; + firstMarkerLongitude?: number; + secondMarkerLatitude?: number; + secondMarkerLongitude?: number; + thirdMarkerLatitude?: number; + thirdMarkerLongitude?: number; + fourthMarkerLatitude?: number; + fourthMarkerLongitude?: number; + commentForMapViewUsage?: string; +} + +const { + commentForMarkerSimulation = "Simulate calculating viewport from visible markers", + firstMarkerLatitude = 37.7749, + firstMarkerLongitude = -122.4194, + secondMarkerLatitude = 37.7849, + secondMarkerLongitude = -122.4094, + thirdMarkerLatitude = 37.7649, + thirdMarkerLongitude = -122.4294, + fourthMarkerLatitude = 37.7949, + fourthMarkerLongitude = -122.3994, + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `@Composable +fun ViewportBoundsExample() { + var viewportBounds by remember { mutableStateOf(null) } + + // ${commentForMarkerSimulation} + val markers = remember { + listOf( + GeoPoint.fromLatLong(${firstMarkerLatitude}, ${firstMarkerLongitude}), + GeoPoint.fromLatLong(${secondMarkerLatitude}, ${secondMarkerLongitude}), + GeoPoint.fromLatLong(${thirdMarkerLatitude}, ${thirdMarkerLongitude}), + GeoPoint.fromLatLong(${fourthMarkerLatitude}, ${fourthMarkerLongitude}) + ) + } + + LaunchedEffect(markers) { + val bounds = GeoRectBounds() + markers.forEach { marker -> + bounds.extend(marker) + } + viewportBounds = bounds + } + + // ${commentForMapViewUsage} + MapView(state = mapViewState) { + // Show all markers + markers.forEach { position -> + Marker( + position = position, + icon = DefaultIcon(fillColor = Color.Blue) + ) + } + + // Show viewport bounds as a polygon + viewportBounds?.let { bounds -> + if (!bounds.isEmpty) { + val sw = bounds.southWest!! + val ne = bounds.northEast!! + + val boundsPolygon = listOf( + sw, + GeoPoint.fromLatLong(sw.latitude, ne.longitude), + ne, + GeoPoint.fromLatLong(ne.latitude, sw.longitude), + sw // Close the polygon + ) + + Polygon( + points = boundsPolygon, + strokeColor = Color.Red, + strokeWidth = 2.dp, + fillColor = Color.Red.copy(alpha = 0.1f) + ) + } + } + } +}`; +--- + + + diff --git a/docs/src/components/core/mapcameraposition/AnimatedCameraExample.astro b/docs/src/components/core/mapcameraposition/AnimatedCameraExample.astro new file mode 100644 index 00000000..a1b8f97a --- /dev/null +++ b/docs/src/components/core/mapcameraposition/AnimatedCameraExample.astro @@ -0,0 +1,77 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForLocations?: string; + commentForAnimationInterval?: string; + animationIntervalMillis?: number; + moveDurationMillis?: number; +} + +const { + commentForLocations = "Animate between multiple locations", + commentForAnimationInterval = "Animate to next location every 5 seconds", + animationIntervalMillis = 5000, + moveDurationMillis = 1000 +} = Astro.props; + +const code = `@Composable +fun AnimatedCameraExample() { + val locations = listOf( + GeoPoint.fromLatLong(37.7749, -122.4194), // San Francisco + GeoPoint.fromLatLong(40.7128, -74.0060), // New York + GeoPoint.fromLatLong(51.5074, -0.1278) // London + ) + + val mapViewState = rememberHereMapViewState( + cameraPosition = MapCameraPosition( + position = locations[0], + zoom = 6.0 + ), + ) + + var currentIndex by remember { mutableStateOf(0) } + + // ${commentForAnimationInterval} + LaunchedEffect(Unit) { + while (true) { + delay(${animationIntervalMillis}) + currentIndex = (currentIndex + 1) % locations.size + + val targetPosition = MapCameraPosition( + position = locations[currentIndex], + zoom = 6.0, + bearing = 0.0, + tilt = 0.0 + ) + mapViewState.moveCameraTo(targetPosition, ${moveDurationMillis}) + } + } + + + // Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView + HereMapView( + state = mapViewState, + modifier = modifier, + ) { + // Add markers for each location + locations.forEachIndexed { index, location -> + Marker( + position = location, + icon = DefaultIcon( + fillColor = if (index == currentIndex) Color.Red else Color.Gray, + label = when (index) { + 0 -> "SF" + 1 -> "NYC" + 2 -> "LON" + else -> "${'$'}index" + } + ) + ) + } + } +}`; +--- + + + diff --git a/docs/src/components/core/mapcameraposition/BearingExamples.astro b/docs/src/components/core/mapcameraposition/BearingExamples.astro new file mode 100644 index 00000000..6f16bcfc --- /dev/null +++ b/docs/src/components/core/mapcameraposition/BearingExamples.astro @@ -0,0 +1,49 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + latitude?: number; + longitude?: number; + bearingNorth?: number; + bearingEast?: number; + bearingRoute?: number; + northUpComment?: string; + eastUpComment?: string; + followingBearingComment?: string; + routeComment?: string; +} + +const { + latitude = 37.7749, + longitude = -122.4194, + bearingNorth = 0.0, + bearingEast = 90.0, + bearingRoute = 135.0, + northUpComment = "North-up (default)", + eastUpComment = "Southeast", + followingBearingComment = "Southeast", + routeComment = "Southeast" +} = Astro.props; + +const code = `// ${northUpComment} +val northUp = MapCameraPosition( + position = GeoPoint.fromLatLong(${latitude}, ${longitude}), + bearing = ${bearingNorth} +) + +// ${eastUpComment} +val eastUp = MapCameraPosition( + position = GeoPoint.fromLatLong(${latitude}, ${longitude}), + bearing = ${bearingEast} +) + +// ${followingBearingComment} +val routeBearing = MapCameraPosition( + position = GeoPoint.fromLatLong(${latitude}, ${longitude}), + bearing = ${bearingRoute}, // ${routeComment} + zoom = 18.0 +)`; +--- + + + diff --git a/docs/src/components/core/mapcameraposition/CameraControlExample.astro b/docs/src/components/core/mapcameraposition/CameraControlExample.astro new file mode 100644 index 00000000..fedb84a7 --- /dev/null +++ b/docs/src/components/core/mapcameraposition/CameraControlExample.astro @@ -0,0 +1,92 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `@Composable +fun CameraControlExample(modifier: Modifier = Modifier) { + val mapViewState = rememberMapLibreMapViewState( + mapDesign = MapLibreDesignType( + id = "debug-tiles", + styleJsonURL = "https://demotiles.maplibre.org/debug-tiles/style.json", + ), + cameraPosition = MapCameraPosition( + position = GeoPoint.fromLatLong(37.7749, -122.4194), + zoom = 15.0 + ), + ) + + Column( + modifier = modifier, + ) { + // Camera controls + Row { + Button( + onClick = { + val newZoom = mapViewState.cameraPosition.copy( + zoom = (mapViewState.cameraPosition.zoom + 1) + .coerceAtMost(21.0), + ) + mapViewState.moveCameraTo(newZoom, 500) + } + ) { + Text("Zoom In") + } + + Button( + onClick = { + val newZoom = mapViewState.cameraPosition.copy( + zoom = (mapViewState.cameraPosition.zoom - 1) + .coerceAtMost(21.0), + ) + mapViewState.moveCameraTo(newZoom, 500) + } + ) { + Text("Zoom Out") + } + + Button( + onClick = { + val newZoom = mapViewState.cameraPosition.copy( + bearing = (mapViewState.cameraPosition.bearing + 45) % 360, + ) + mapViewState.moveCameraTo(newZoom, 500) + } + ) { + Text("Rotate") + } + } + + // Tilt slider + Slider( + value = mapViewState.cameraPosition.tilt.toFloat(), + onValueChange = { tilt -> + val newZoom = mapViewState.cameraPosition.copy( + tilt = tilt.toDouble(), + ) + mapViewState.moveCameraTo(newZoom) + }, + valueRange = 0f..80f + ) + + // ${commentForMapViewUsage} + MapLibreMapView( + state = mapViewState, + ) { + Marker( + position = mapViewState.cameraPosition.position, + icon = DefaultIcon(fillColor = Color.Red) + ) + } + } +}`; +--- + + + diff --git a/docs/src/components/core/mapcameraposition/CustomCameraPositionsExample.astro b/docs/src/components/core/mapcameraposition/CustomCameraPositionsExample.astro new file mode 100644 index 00000000..0e0ceb9e --- /dev/null +++ b/docs/src/components/core/mapcameraposition/CustomCameraPositionsExample.astro @@ -0,0 +1,55 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForBasic?: string; + commentForAerial?: string; + commentForPadded?: string; + latitude?: number; + longitude?: number; + basicZoom?: number; + aerialZoom?: number; + aerialBearing?: number; + aerialTilt?: number; + paddedZoom?: number; + paddingTop?: number; + paddingLeft?: number; + paddingBottom?: number; + paddingRight?: number; +} + +const { + commentForBasic = "Basic camera position", + commentForAerial = "Camera with bearing and tilt", + commentForPadded = "Camera with padding for UI elements", + latitude = 37.7749, + longitude = -122.4194, + basicZoom = 15.0, + aerialZoom = 18.0, + aerialBearing = 45.0, + aerialTilt = 60.0, + paddedZoom = 14.0, + paddingTop = 100.0, + paddingLeft = 50.0, + paddingBottom = 200.0, + paddingRight = 50.0 +} = Astro.props; + +const code = `// ${commentForBasic} +val sanFrancisco = MapCameraPosition( + position = GeoPoint.fromLatLong(${latitude}, ${longitude}), + zoom = ${basicZoom} +) + +// ${commentForAerial} +val aerialView = MapCameraPosition( + position = GeoPoint.fromLatLong(${latitude}, ${longitude}), + zoom = ${aerialZoom}, + bearing = ${aerialBearing}, // Northeast direction + tilt = ${aerialTilt} // Angled view +) +`; +--- + + + diff --git a/docs/src/components/core/mapcameraposition/DefaultCameraPositionExample.astro b/docs/src/components/core/mapcameraposition/DefaultCameraPositionExample.astro new file mode 100644 index 00000000..21f43e97 --- /dev/null +++ b/docs/src/components/core/mapcameraposition/DefaultCameraPositionExample.astro @@ -0,0 +1,17 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForDefaultPosition?: string; +} + +const { + commentForDefaultPosition = "Default camera position at origin" +} = Astro.props; + +const code = `// ${commentForDefaultPosition} +val defaultPosition = MapCameraPosition.Default`; +--- + + + diff --git a/docs/src/components/core/mapcameraposition/MapCameraPositionImpl.astro b/docs/src/components/core/mapcameraposition/MapCameraPositionImpl.astro new file mode 100644 index 00000000..b43ae339 --- /dev/null +++ b/docs/src/components/core/mapcameraposition/MapCameraPositionImpl.astro @@ -0,0 +1,15 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `data class MapCameraPosition( + override val position: GeoPoint, + override val zoom: Double = 0.0, + override val bearing: Double = 0.0, + override val tilt: Double = 0.0, + override val paddings: MapPaddingsInterface? = MapPaddings.Zeros, + override val visibleRegion: VisibleRegion? = null +) : MapCameraPositionInterface`; +--- + + + diff --git a/docs/src/components/core/mapcameraposition/MapCameraPositionInterface.astro b/docs/src/components/core/mapcameraposition/MapCameraPositionInterface.astro new file mode 100644 index 00000000..f875c18f --- /dev/null +++ b/docs/src/components/core/mapcameraposition/MapCameraPositionInterface.astro @@ -0,0 +1,15 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `interface MapCameraPositionInterface { + val position: GeoPointInterface + val zoom: Double + val bearing: Double + val tilt: Double + val paddings: MapPaddingsInterface? + val visibleRegion: VisibleRegion? +}`; +--- + + + diff --git a/docs/src/components/core/mapcameraposition/NavigationCameraExample.astro b/docs/src/components/core/mapcameraposition/NavigationCameraExample.astro new file mode 100644 index 00000000..c957afa5 --- /dev/null +++ b/docs/src/components/core/mapcameraposition/NavigationCameraExample.astro @@ -0,0 +1,25 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + navigationZoom?: number; + navigationTilt?: number; + commentForBearing?: string; +} + +const { + navigationZoom = 18.0, + navigationTilt = 60.0, + commentForBearing = "Direction of travel" +} = Astro.props; + +const code = `val navigationCamera = MapCameraPosition( + position = currentRoutePosition, + zoom = ${navigationZoom}, + bearing = currentHeading, // ${commentForBearing} + tilt = ${navigationTilt} // Angled for street view +)`; +--- + + + diff --git a/docs/src/components/core/mapcameraposition/ShowMultiplePointsExample.astro b/docs/src/components/core/mapcameraposition/ShowMultiplePointsExample.astro new file mode 100644 index 00000000..0d7c4fa2 --- /dev/null +++ b/docs/src/components/core/mapcameraposition/ShowMultiplePointsExample.astro @@ -0,0 +1,26 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForZoomCalculation?: string; +} + +const { + commentForZoomCalculation = "Custom calculation" +} = Astro.props; + +const code = `// Calculate bounds containing all points, then set appropriate zoom +val allPoints = listOf(/* your points */) +val bounds = GeoRectBounds() +allPoints.forEach { bounds.extend(it) } + +val centerCamera = MapCameraPosition( + position = bounds.center ?: GeoPoint.fromLatLong(0.0, 0.0), + zoom = calculateZoomForBounds(bounds), // ${commentForZoomCalculation} + bearing = 0.0, + tilt = 0.0 +)`; +--- + + + diff --git a/docs/src/components/core/mapcameraposition/TiltExamples.astro b/docs/src/components/core/mapcameraposition/TiltExamples.astro new file mode 100644 index 00000000..e3d50133 --- /dev/null +++ b/docs/src/components/core/mapcameraposition/TiltExamples.astro @@ -0,0 +1,55 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + latitude?: number; + longitude?: number; + topDownTilt?: number; + angledTilt?: number; + angledZoom?: number; + streetTilt?: number; + streetBearing?: number; + streetZoom?: number; + topDownComment?: string; + angledComment?: string; + streetLevelComment?: string; +} + +const { + latitude = 37.7749, + longitude = -122.4194, + topDownTilt = 0.0, + angledTilt = 30.0, + angledZoom = 16.0, + streetTilt = 80.0, + streetBearing = 45.0, + streetZoom = 19.0, + topDownComment = "Top-down view (default)", + angledComment = "Slight angle for depth", + streetLevelComment = "Maximum tilt for street-level view" +} = Astro.props; + +const code = `// ${topDownComment} +val topDown = MapCameraPosition( + position = GeoPoint.fromLatLong(${latitude}, ${longitude}), + tilt = ${topDownTilt} +) + +// ${angledComment} +val angled = MapCameraPosition( + position = GeoPoint.fromLatLong(${latitude}, ${longitude}), + tilt = ${angledTilt}, + zoom = ${angledZoom} +) + +// ${streetLevelComment} +val streetLevel = MapCameraPosition( + position = GeoPoint.fromLatLong(${latitude}, ${longitude}), + tilt = ${streetTilt}, + bearing = ${streetBearing}, + zoom = ${streetZoom} +)`; +--- + + + diff --git a/docs/src/components/core/mapcameraposition/UserLocationCameraExample.astro b/docs/src/components/core/mapcameraposition/UserLocationCameraExample.astro new file mode 100644 index 00000000..1fa76a01 --- /dev/null +++ b/docs/src/components/core/mapcameraposition/UserLocationCameraExample.astro @@ -0,0 +1,23 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForZoom?: string; + zoomLevel?: number; +} + +const { + commentForZoom = "Street level detail", + zoomLevel = 16.0 +} = Astro.props; + +const code = `val userLocationCamera = MapCameraPosition( + position = userCurrentLocation, + zoom = ${zoomLevel}, // ${commentForZoom} + bearing = 0.0, + tilt = 0.0 +)`; +--- + + + diff --git a/docs/src/components/core/mapcameraposition/VisibleRegionDataClass.astro b/docs/src/components/core/mapcameraposition/VisibleRegionDataClass.astro new file mode 100644 index 00000000..1986de7d --- /dev/null +++ b/docs/src/components/core/mapcameraposition/VisibleRegionDataClass.astro @@ -0,0 +1,30 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + boundsComment?: string; + nearLeftComment?: string; + nearRightComment?: string; + farLeftComment?: string; + farRightComment?: string; +} + +const { + boundsComment = "Overall bounding rectangle", + nearLeftComment = "Bottom-left corner (near to camera)", + nearRightComment = "Bottom-right corner (near to camera)", + farLeftComment = "Top-left corner (far from camera)", + farRightComment = "Top-right corner (far from camera)" +} = Astro.props; + +const code = `data class VisibleRegion( + val bounds: GeoRectBounds, // ${boundsComment} + val nearLeft: GeoPointInterface?, // ${nearLeftComment} + val nearRight: GeoPointInterface?, // ${nearRightComment} + val farLeft: GeoPointInterface?, // ${farLeftComment} + val farRight: GeoPointInterface? // ${farRightComment} +)`; +--- + + + diff --git a/docs/src/components/core/mapcameraposition/VisibleRegionExample.astro b/docs/src/components/core/mapcameraposition/VisibleRegionExample.astro new file mode 100644 index 00000000..0172d4fc --- /dev/null +++ b/docs/src/components/core/mapcameraposition/VisibleRegionExample.astro @@ -0,0 +1,65 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; + commentForDisplayRegion?: string; + commentForShowBounds?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView", + commentForDisplayRegion = "Display visible region info", + commentForShowBounds = "Show bounds as a polygon" +} = Astro.props; + +const code = `@Composable +fun VisibleRegionExample() { + + val mapViewState = rememberMapboxMapViewState( + cameraPosition = MapCameraPosition( + position = GeoPoint.fromLatLong(37.7749, -122.4194), + zoom = 15.0 + ), + ) + var visibleRegionInfo by remember { mutableStateOf(null) } + + // ${commentForMapViewUsage} + MapboxMapView( + state = mapViewState, + modifier = modifier, + onCameraMoveEnd = { cameraPosition -> + cameraPosition.visibleRegion?.let { visibleRegion -> + visibleRegionInfo = visibleRegion + } + }, + ) { + // ${commentForDisplayRegion} + visibleRegionInfo?.let { region -> + // ${commentForShowBounds} + region.bounds.let { bounds -> + if (!bounds.isEmpty) { + val sw = bounds.southWest!! + val ne = bounds.northEast!! + + Polygon( + points = listOf( + sw, + GeoPoint.fromLatLong(sw.latitude, ne.longitude), + ne, + GeoPoint.fromLatLong(ne.latitude, sw.longitude), + sw + ), + strokeColor = Color.Blue, + strokeWidth = 2.dp, + fillColor = Color.Blue.copy(alpha = 0.1f) + ) + } + } + } + } +}`; +--- + + + diff --git a/docs/src/components/core/mapcameraposition/ZoomLevelsExample.astro b/docs/src/components/core/mapcameraposition/ZoomLevelsExample.astro new file mode 100644 index 00000000..da52e7c9 --- /dev/null +++ b/docs/src/components/core/mapcameraposition/ZoomLevelsExample.astro @@ -0,0 +1,52 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + worldLatitude?: number; + worldLongitude?: number; + worldZoom?: number; + worldComment?: string; + cityLatitude?: number; + cityLongitude?: number; + cityZoom?: number; + cityComment?: string; + streetLatitude?: number; + streetLongitude?: number; + streetZoom?: number; + streetComment?: string; +} + +const { + worldLatitude = 0.0, + worldLongitude = 0.0, + worldZoom = 2.0, + worldComment = "Show continents", + cityLatitude = 37.7749, + cityLongitude = -122.4194, + cityZoom = 12.0, + cityComment = "Show entire city", + streetLatitude = 37.7749, + streetLongitude = -122.4194, + streetZoom = 17.0, + streetComment = "Show individual streets" +} = Astro.props; + +const code = `// Different zoom levels for different use cases +val worldView = MapCameraPosition( + position = GeoPoint.fromLatLong(${worldLatitude}, ${worldLongitude}), + zoom = ${worldZoom} // ${worldComment} +) + +val cityView = MapCameraPosition( + position = GeoPoint.fromLatLong(${cityLatitude}, ${cityLongitude}), + zoom = ${cityZoom} // ${cityComment} +) + +val streetView = MapCameraPosition( + position = GeoPoint.fromLatLong(${streetLatitude}, ${streetLongitude}), + zoom = ${streetZoom} // ${streetComment} +)`; +--- + + + diff --git a/docs/src/components/core/mapviewholder/AnalyticsIntegrationExample.astro b/docs/src/components/core/mapviewholder/AnalyticsIntegrationExample.astro new file mode 100644 index 00000000..1a1c45d5 --- /dev/null +++ b/docs/src/components/core/mapviewholder/AnalyticsIntegrationExample.astro @@ -0,0 +1,48 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForTrackEvents?: string; + commentForTrackStyle?: string; +} + +const { + commentForTrackEvents = "Track custom map events", + commentForTrackStyle = "Track style changes" +} = Astro.props; + +const code = `@Composable +fun AnalyticsIntegration() { + val mapViewState = remember { MapboxViewState() } + + LaunchedEffect(mapViewState) { + mapViewState.getMapViewHolder()?.let { holder -> + val mapboxMap = holder.map + + // ${commentForTrackEvents} + mapboxMap.addOnMapClickListener { point -> + Analytics.track("map_click", mapOf( + "lat" to point.latitude, + "lng" to point.longitude, + "zoom" to mapboxMap.cameraPosition.zoom + )) + true + } + + // ${commentForTrackStyle} + mapboxMap.addOnStyleLoadedListener { + Analytics.track("style_loaded", mapOf( + "style_id" to mapboxMap.style?.styleURI + )) + } + } + } + + MapboxMapView(state = mapViewState) { + // Your MapConductor components + } +}`; +--- + + + diff --git a/docs/src/components/core/mapviewholder/ArcGISMapViewHolder.astro b/docs/src/components/core/mapviewholder/ArcGISMapViewHolder.astro new file mode 100644 index 00000000..9d2899d5 --- /dev/null +++ b/docs/src/components/core/mapviewholder/ArcGISMapViewHolder.astro @@ -0,0 +1,15 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `typealias ArcGISMapViewHolder = MapViewHolderInterface + +class ArcGISMapViewHolder( + override val mapView: WrapSceneView, + override val map: SceneView, +) : MapViewHolderInterface { + fun toScreenOffset(position: GeoPointInterface): Offset? + suspend fun fromScreenOffset(offset: Offset): GeoPoint? +}`; +--- + + diff --git a/docs/src/components/core/mapviewholder/ArcGISMapViewHolderAccess.astro b/docs/src/components/core/mapviewholder/ArcGISMapViewHolderAccess.astro new file mode 100644 index 00000000..5d7decc3 --- /dev/null +++ b/docs/src/components/core/mapviewholder/ArcGISMapViewHolderAccess.astro @@ -0,0 +1,10 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `// ArcGIS +val arcgisState = rememberArcGISMapViewState() +val arcgisHolder: ArcGISMapViewHolder? = arcgisState.getMapViewHolder();` +--- + + + diff --git a/docs/src/components/core/mapviewholder/ArcGISMapViewHolderExample.astro b/docs/src/components/core/mapviewholder/ArcGISMapViewHolderExample.astro new file mode 100644 index 00000000..73e486f6 --- /dev/null +++ b/docs/src/components/core/mapviewholder/ArcGISMapViewHolderExample.astro @@ -0,0 +1,98 @@ + +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentCameraPosition?: string; + commentAuthenticatorState?: string; + commentViewHolderVariable?: string; + commentTrafficLayer?: string; + commentAuthenticatorStateParam?: string; + commentPortalUrl?: string; + commentRedirectUrl?: string; + commentClientId?: string; + commentOptional?: string; + commentClientSecret?: string; + commentClientSecretOmit?: string; + commentGetViewHolder?: string; + commentAuthenticatorUI?: string; +} + +const { + commentCameraPosition = '地図のカメラ位置', + commentAuthenticatorState = 'AuthenticatorStateを設定', + commentViewHolderVariable = 'ViewHolderの保持', + commentTrafficLayer = '交通情報のレイヤーを表示', + commentAuthenticatorStateParam = 'ログインダイアログを表示する AuthenticatorState', + commentPortalUrl = 'ArcGISポータルのURL', + commentRedirectUrl = 'OAuth2アプリケーションのリダイレクトURL', + commentClientId = 'OAuth2アプリケーションのクライアントID', + commentOptional = '(オプション)', + commentClientSecret = 'OAuth2アプリケーションのクライアントシークレット', + commentClientSecretOmit = '省略した場合はログインダイアログが表示されます', + commentGetViewHolder = 'ViewHolderの取得', + commentAuthenticatorUI = '認証UI(ユーザーログイン用)。ハイブリッド認証のフォールバックで使用されます。', +} = Astro.props; + +const code = `@Composable +fun BasicMapExample( + modifier: Modifier = Modifier +) { + // ${commentCameraPosition} + val mapViewState = rememberArcGISMapViewState( + cameraPosition = MapCameraPosition( + position = GeoPoint.fromLatLong(40.40195, -3.68698), + zoom = 8.0 + ), + ) + + // ${commentAuthenticatorState} + val authenticatorState = remember { AuthenticatorState() } + + // ${commentViewHolderVariable} + var arcGisMapViewHolder by remember { mutableStateOf(null) } + + LaunchedEffect(arcGisMapViewHolder) { + // ${commentTrafficLayer} + arcGisMapViewHolder?.let { holder -> + val trafficLayer = + ArcGISMapImageLayer("https://traffic.arcgis.com/arcgis/rest/services/World/Traffic/MapServer") + holder.map.scene!!.operationalLayers.add(trafficLayer) + } + } + + ArcGISMapView( + state = mapViewState, + modifier = modifier.fillMaxSize(), + sdkInitialize = { context -> + ArcGISOAuthHybridInitialize( + // ${commentAuthenticatorStateParam} + authenticatorState = authenticatorState + + // ${commentPortalUrl} + portalUrl = "https://(your).maps.arcgis.com/", + + // ${commentRedirectUrl} + redirectUrl = "(application redirectUrl)", + + // ${commentClientId} + clientId = "(application clientId)", + + // ${commentOptional} + // ${commentClientSecret} + // ${commentClientSecretOmit} + clientSecret = "(application client secret)", + ) + }, + onMapLoaded = { + // ${commentGetViewHolder} + arcGisMapViewHolder = mapViewState.getMapViewHolder() + } + ) {} + + // ${commentAuthenticatorUI} + Authenticator(authenticatorState = authenticatorState) +}`; +--- + + diff --git a/docs/src/components/core/mapviewholder/CustomStyledMapExample.astro b/docs/src/components/core/mapviewholder/CustomStyledMapExample.astro new file mode 100644 index 00000000..6da9836d --- /dev/null +++ b/docs/src/components/core/mapviewholder/CustomStyledMapExample.astro @@ -0,0 +1,47 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForInitWait?: string; + commentForApplyStyle?: string; + commentForConfigureUi?: string; + commentForMapViewUsage?: string; +} + +const { + commentForInitWait = "Wait for map initialization", + commentForApplyStyle = "Apply custom map style", + commentForConfigureUi = "Configure map UI", + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `@Composable +fun CustomStyledMap() { + val mapViewState = rememberGoogleMapViewState() + + LaunchedEffect(mapViewState) { + // ${commentForInitWait} + delay(1000) + + mapViewState.getMapViewHolder()?.let { holder -> + val googleMap = holder.map + + // ${commentForApplyStyle} + val styleJson = loadStyleFromAssets(context, "custom_style.json") + googleMap.setMapStyle(MapStyleOptions(styleJson)) + + // ${commentForConfigureUi} + googleMap.uiSettings.isMyLocationButtonEnabled = false + googleMap.uiSettings.isCompassEnabled = true + } + } + + // ${commentForMapViewUsage} + GoogleMapView(state = mapViewState) { + // Your MapConductor components + } +}`; +--- + + + diff --git a/docs/src/components/core/mapviewholder/GoogleMapViewHolder.astro b/docs/src/components/core/mapviewholder/GoogleMapViewHolder.astro new file mode 100644 index 00000000..b5a96ddf --- /dev/null +++ b/docs/src/components/core/mapviewholder/GoogleMapViewHolder.astro @@ -0,0 +1,16 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `typealias GoogleMapViewHolder = MapViewHolderInterface + +class GoogleMapViewHolder( + override val mapView: MapView, + override val map: GoogleMap, +) : MapViewHolderInterface { + fun toScreenOffset(position: GeoPointInterface): Offset? + suspend fun fromScreenOffset(offset: Offset): GeoPoint? +}`; +--- + + + diff --git a/docs/src/components/core/mapviewholder/GoogleMapViewHolderAccess.astro b/docs/src/components/core/mapviewholder/GoogleMapViewHolderAccess.astro new file mode 100644 index 00000000..3566eafc --- /dev/null +++ b/docs/src/components/core/mapviewholder/GoogleMapViewHolderAccess.astro @@ -0,0 +1,10 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `// Google Maps +val googleMapState = rememberGoogleMapViewState() +val googleHolder: GoogleMapViewHolder? = googleMapState.getMapViewHolder()` +--- + + + diff --git a/docs/src/components/core/mapviewholder/GoogleMapViewHolderExample.astro b/docs/src/components/core/mapviewholder/GoogleMapViewHolderExample.astro new file mode 100644 index 00000000..8ca7d6b3 --- /dev/null +++ b/docs/src/components/core/mapviewholder/GoogleMapViewHolderExample.astro @@ -0,0 +1,77 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentCameraPosition?: string; + commentRecompose?: string; + commentGetViewHolder?: string; + commentNormalMap?: string; + commentSimplifiedMap?: string; +} + +const { + commentCameraPosition = "地図のカメラ位置", + commentRecompose = "mutableStateOfにすることで、mapStyleが変化したら 再描画", + commentGetViewHolder = "ViewHolderの取得", + commentNormalMap = "通常のGoogle Maps", + commentSimplifiedMap = "地図を簡略化したデザイン" +} = Astro.props; + +const code = `@Composable +fun MapViewHolderGoogleMapsExample(modifier: Modifier = Modifier) { + val context = LocalContext.current + + // ${commentCameraPosition} + val mapViewState = rememberGoogleMapViewState( + cameraPosition = MapCameraPosition( + position = GeoPoint.fromLatLong(28.53456, 77.192845), + zoom = 12.0 + ), + ) + + // ${commentRecompose} + var mapStyle by remember { mutableStateOf(null) } + + // ${commentGetViewHolder} + val googleMapViewHolder = mapViewState.getMapViewHolder() + LaunchedEffect(googleMapViewHolder, mapStyle) { + if (googleMapViewHolder == null) return@LaunchedEffect + googleMapViewHolder.map.setMapStyle(mapStyle) + } + + Column(modifier = modifier) { + Row( + modifier = Modifier.fillMaxWidth(), + ) { + Spacer(modifier = Modifier.size(20.dp)) + + // ${commentNormalMap} + Button(onClick = { + mapStyle = null + }) { + Text( + text = "Normal" + ) + } + Spacer(modifier = Modifier.size(20.dp)) + + // ${commentSimplifiedMap} + Button(onClick = { + mapStyle = MapStyleOptions.loadRawResourceStyle(context, R.raw.style_map) + }) { + Text( + text = "Simplified" + ) + } + } + + GoogleMapView( + state = mapViewState, + modifier = Modifier.fillMaxSize(), + ) {} + } +}`; +--- + + + diff --git a/docs/src/components/core/mapviewholder/HereMapViewHolder.astro b/docs/src/components/core/mapviewholder/HereMapViewHolder.astro new file mode 100644 index 00000000..b6c502d4 --- /dev/null +++ b/docs/src/components/core/mapviewholder/HereMapViewHolder.astro @@ -0,0 +1,15 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `typealias HereViewHolder = MapViewHolderInterface + +class HereViewHolder( + override val mapView: MapView, + override val map: MapScene, +) : MapViewHolderInterface { + fun toScreenOffset(position: GeoPointInterface): Offset? + suspend fun fromScreenOffset(offset: Offset): GeoPoint? +}`; +--- + + diff --git a/docs/src/components/core/mapviewholder/HereMapViewHolderAccess.astro b/docs/src/components/core/mapviewholder/HereMapViewHolderAccess.astro new file mode 100644 index 00000000..ab989f9b --- /dev/null +++ b/docs/src/components/core/mapviewholder/HereMapViewHolderAccess.astro @@ -0,0 +1,9 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `// HERE Maps +val hereState = rememberHereMapViewState() +val hereHolder: HereMapViewHolder? = hereState.getMapViewHolder()`; +--- + + diff --git a/docs/src/components/core/mapviewholder/HereMapViewHolderAccessExample copy 2.astro b/docs/src/components/core/mapviewholder/HereMapViewHolderAccessExample copy 2.astro new file mode 100644 index 00000000..5cceba69 --- /dev/null +++ b/docs/src/components/core/mapviewholder/HereMapViewHolderAccessExample copy 2.astro @@ -0,0 +1,10 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `// HERE Maps +val hereState = rememberHereMapViewState() +val hereHolder: HereViewHolder? = hereState.getMapViewHolder()` +--- + + + diff --git a/docs/src/components/core/mapviewholder/HereMapViewHolderExample.astro b/docs/src/components/core/mapviewholder/HereMapViewHolderExample.astro new file mode 100644 index 00000000..c42763ca --- /dev/null +++ b/docs/src/components/core/mapviewholder/HereMapViewHolderExample.astro @@ -0,0 +1,78 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentCameraPosition?: string; + commentMapScheme?: string; + commentGetViewHolder?: string; + commentNormalDay?: string; + commentSatellite?: string; +} + +const { + commentCameraPosition = "地図のカメラ位置", + commentMapScheme = "mutableStateOfにすることで、mapSchemeが変化したら 再描画", + commentGetViewHolder = "ViewHolderの取得", + commentNormalDay = "通常の地図表示", + commentSatellite = "衛星画像表示" +} = Astro.props; + +const code = `@Composable +fun MapViewHolderHereMapsExample(modifier: Modifier = Modifier) { + // ${commentCameraPosition} + val mapViewState = rememberHereMapViewState( + cameraPosition = MapCameraPosition( + position = GeoPoint.fromLatLong(35.6812, 139.7671), + zoom = 12.0 + ), + ) + + // ${commentMapScheme} + var mapScheme by remember { mutableStateOf(MapScheme.NORMAL_DAY) } + + // ${commentGetViewHolder} + val hereMapViewHolder = mapViewState.getMapViewHolder() + LaunchedEffect(hereMapViewHolder, mapScheme) { + if (hereMapViewHolder == null) return@LaunchedEffect + hereMapViewHolder.map.loadScene(mapScheme) { errorCode -> + if (errorCode != null) { + Log.e("HERE", "Failed to load map scene: \${errorCode.name}") + } + } + } + + Column(modifier = modifier) { + Row( + modifier = Modifier.fillMaxWidth(), + ) { + Spacer(modifier = Modifier.size(20.dp)) + + // ${commentNormalDay} + Button(onClick = { + mapScheme = MapScheme.NORMAL_DAY + }) { + Text( + text = "Normal" + ) + } + Spacer(modifier = Modifier.size(20.dp)) + + // ${commentSatellite} + Button(onClick = { + mapScheme = MapScheme.SATELLITE + }) { + Text( + text = "Satellite" + ) + } + } + + HereMapView( + state = mapViewState, + modifier = Modifier.fillMaxSize(), + ) {} + } +}`; +--- + + diff --git a/docs/src/components/core/mapviewholder/HereViewHolderExample.astro b/docs/src/components/core/mapviewholder/HereViewHolderExample.astro new file mode 100644 index 00000000..67e555e8 --- /dev/null +++ b/docs/src/components/core/mapviewholder/HereViewHolderExample.astro @@ -0,0 +1,40 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForAccessApis?: string; + commentForUseFeatures?: string; + commentForSearchResults?: string; + commentForRouting?: string; +} + +const { + commentForAccessApis = "Access native HERE SDK APIs", + commentForUseFeatures = "Use HERE specific features", + commentForSearchResults = "Handle HERE search results", + commentForRouting = "Configure and use routing" +} = Astro.props; + +const code = `typealias HereViewHolder = MapViewHolderInterface + +// ${commentForAccessApis} +hereHolder?.let { holder -> + val hereMapView: MapView = holder.mapView + val mapScene: MapScene = holder.map + + // ${commentForUseFeatures} + val searchEngine = SearchEngine() + val textQuery = TextQuery("coffee shops", geoCoordinates) + + searchEngine.search(textQuery) { searchError, searchResults -> + // ${commentForSearchResults} + } + + // HERE routing + val routingEngine = RoutingEngine() + // ${commentForRouting} +}`; +--- + + + diff --git a/docs/src/components/core/mapviewholder/LifecycleAwareMapExample.astro b/docs/src/components/core/mapviewholder/LifecycleAwareMapExample.astro new file mode 100644 index 00000000..19cb65f6 --- /dev/null +++ b/docs/src/components/core/mapviewholder/LifecycleAwareMapExample.astro @@ -0,0 +1,46 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForLifecycle?: string; +} + +const { + commentForLifecycle = "Handle map lifecycle events" +} = Astro.props; + +const code = `@Composable +fun LifecycleAwareMap() { + val mapViewState = rememberGoogleMapViewState() + val lifecycleOwner = LocalLifecycleOwner.current + + DisposableEffect(lifecycleOwner) { + val observer = LifecycleEventObserver { _, event -> + mapViewState.getMapViewHolder()?.let { holder -> + val mapView = holder.mapView + + when (event) { + Lifecycle.Event.ON_RESUME -> mapView.onResume() + Lifecycle.Event.ON_PAUSE -> mapView.onPause() + Lifecycle.Event.ON_START -> mapView.onStart() + Lifecycle.Event.ON_STOP -> mapView.onStop() + Lifecycle.Event.ON_DESTROY -> mapView.onDestroy() + else -> { } + } + } + } + + lifecycleOwner.lifecycle.addObserver(observer) + onDispose { + lifecycleOwner.lifecycle.removeObserver(observer) + } + } + + GoogleMapView(state = mapViewState) { + // Your MapConductor components + } +}`; +--- + + + diff --git a/docs/src/components/core/mapviewholder/MapLibreMapViewHolderAccessExample.astro b/docs/src/components/core/mapviewholder/MapLibreMapViewHolderAccessExample.astro new file mode 100644 index 00000000..1f6d3e1d --- /dev/null +++ b/docs/src/components/core/mapviewholder/MapLibreMapViewHolderAccessExample.astro @@ -0,0 +1,10 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `// MapLibre +val maplibreState = rememberMapLibreMapViewState() +val maplibreHolder: MapLibreMapViewHolderInterface? = maplibreState.getMapViewHolder()`; +--- + + + diff --git a/docs/src/components/core/mapviewholder/MapViewHolderAccessExample.astro b/docs/src/components/core/mapviewholder/MapViewHolderAccessExample.astro new file mode 100644 index 00000000..87619b47 --- /dev/null +++ b/docs/src/components/core/mapviewholder/MapViewHolderAccessExample.astro @@ -0,0 +1,16 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `// Any provider state exposes getMapViewHolder() +val state = rememberGoogleMapViewState() + +// May be null until the map is initialized +val holder = state.getMapViewHolder() + +// Use the concrete holder type when you need provider-specific APIs +// (e.g. GoogleMapViewHolder / MapboxMapViewHolder / MapLibreMapViewHolder / ...) +// holder?.googleMap?.uiSettings?.isZoomControlsEnabled = false` +--- + + + diff --git a/docs/src/components/core/mapviewholder/MapViewHolderInterface.astro b/docs/src/components/core/mapviewholder/MapViewHolderInterface.astro new file mode 100644 index 00000000..6c7c4d01 --- /dev/null +++ b/docs/src/components/core/mapviewholder/MapViewHolderInterface.astro @@ -0,0 +1,11 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `interface MapViewHolderInterface { + val mapView: ActualMapViewType + val map: ActualMapType +}`; +--- + + + diff --git a/docs/src/components/core/mapviewholder/MapboxMapViewHolder.astro b/docs/src/components/core/mapviewholder/MapboxMapViewHolder.astro new file mode 100644 index 00000000..eca77696 --- /dev/null +++ b/docs/src/components/core/mapviewholder/MapboxMapViewHolder.astro @@ -0,0 +1,19 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `typealias MapboxMapViewHolder = MapViewHolderInterface + +class MapboxMapViewHolder( + override val mapView: MapView, + override val map: MapboxMap, +) : MapViewHolderInterface, + MapboxLifecycleObserver { + fun toScreenOffset(position: GeoPointInterface): Offset? + fun fromScreenOffsetSync(offset: Offset): GeoPoint? + fun fromScreenOffset(coordinate: ScreenCoordinate): GeoPoint? + suspend fun fromScreenOffset(offset: Offset): GeoPoint? +}`; +--- + + + diff --git a/docs/src/components/core/mapviewholder/MapboxMapViewHolderAccess.astro b/docs/src/components/core/mapviewholder/MapboxMapViewHolderAccess.astro new file mode 100644 index 00000000..f046fde8 --- /dev/null +++ b/docs/src/components/core/mapviewholder/MapboxMapViewHolderAccess.astro @@ -0,0 +1,10 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `// Mapbox +val mapboxState = rememberMapboxMapViewState() +val mapboxHolder: MapboxMapViewHolder? = mapboxState.getMapViewHolder()`; +--- + + + diff --git a/docs/src/components/core/mapviewholder/MapboxMapViewHolderExample.astro b/docs/src/components/core/mapviewholder/MapboxMapViewHolderExample.astro new file mode 100644 index 00000000..f50a4a2c --- /dev/null +++ b/docs/src/components/core/mapviewholder/MapboxMapViewHolderExample.astro @@ -0,0 +1,101 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentPermissionLogic?: string; + commentExplanationNeeded?: string; + commentPermissionDenied?: string; + commentGetViewHolder?: string; +} + +const { + commentPermissionLogic = "Permission sensitive logic called here, such as activating the Maps SDK's LocationComponent to show the device's location", + commentExplanationNeeded = "Display an explanation to obtain the location access permissions", + commentPermissionDenied = "User denied the permission", + commentGetViewHolder = "ViewHolderの取得" +} = Astro.props; + +const code = ` +class MainActivity : ComponentActivity() { + lateinit var permissionsManager: PermissionsManager + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + + if (PermissionsManager.areLocationPermissionsGranted(this)) { + // ${commentPermissionLogic} + } else { + permissionsManager = PermissionsManager(this.permissionsListener) + permissionsManager.requestLocationPermissions(this) + } + + setContent { + MapConductorSDKTheme { + Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> + BasicMapExample( + modifier = + Modifier + .padding(innerPadding) + .fillMaxSize(), + ) + } + } + } + } + + var permissionsListener: PermissionsListener = object : PermissionsListener { + override fun onExplanationNeeded(permissionsToExplain: List) { + // ${commentExplanationNeeded} + } + + override fun onPermissionResult(granted: Boolean) { + if (granted) { + // ${commentPermissionLogic} + } else { + // ${commentPermissionDenied} + } + } + } +} + +@Composable +fun BasicMapExample(modifier: Modifier = Modifier) { + val mapViewState = rememberMapboxMapViewState( + cameraPosition = MapCameraPosition( + position = GeoPoint.fromLatLong(35.706400, 139.763635), + zoom = 13.0 + ), + ) + + // ${commentGetViewHolder} + var mapboxMapViewHolder by remember { mutableStateOf(null) } + LaunchedEffect(mapboxMapViewHolder) { + mapboxMapViewHolder?.let { holder -> + with(holder.mapView) { + location.locationPuck = createDefault2DPuck(withBearing = true) + location.enabled = true + location.pulsingEnabled = true + location.puckBearing = PuckBearing.COURSE + location.puckBearingEnabled = true + viewport.transitionTo( + targetState = viewport.makeFollowPuckViewportState(), + transition = viewport.makeImmediateViewportTransition() + ) + } + } + } + + MapboxMapView( + state = mapViewState, + modifier = modifier, + onMapLoaded = { + mapboxMapViewHolder = mapViewState.getMapViewHolder() + } + ) {} +} +`; +--- + + + diff --git a/docs/src/components/core/mapviewholder/NullSafetyAccessExample.astro b/docs/src/components/core/mapviewholder/NullSafetyAccessExample.astro new file mode 100644 index 00000000..445cad2a --- /dev/null +++ b/docs/src/components/core/mapviewholder/NullSafetyAccessExample.astro @@ -0,0 +1,35 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForSafeAccess?: string; + commentForUnavailable?: string; +} + +const { + commentForSafeAccess = "Safe to access native APIs", + commentForUnavailable = "Map not yet initialized or unavailable" +} = Astro.props; + +const code = `fun accessNativeMap(mapViewState: GoogleMapViewState) { + val holder = mapViewState.getMapViewHolder() + + if (holder != null) { + // ${commentForSafeAccess} + val googleMap = holder.map + val mapView = holder.mapView + + // Use native features + googleMap.setOnMarkerClickListener { marker -> + // Handle marker click + true + } + } else { + // ${commentForUnavailable} + Log.w("MapAccess", "MapViewHolderInterface not available") + } +}`; +--- + + + diff --git a/docs/src/components/core/mapviewholder/PerformanceOptimizedMapExample.astro b/docs/src/components/core/mapviewholder/PerformanceOptimizedMapExample.astro new file mode 100644 index 00000000..f2604bc6 --- /dev/null +++ b/docs/src/components/core/mapviewholder/PerformanceOptimizedMapExample.astro @@ -0,0 +1,44 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForPerformanceSettings?: string; + commentForOptimizeUseCase?: string; + commentForLevelOfDetail?: string; +} + +const { + commentForPerformanceSettings = "HERE-specific performance settings", + commentForOptimizeUseCase = "Optimize for specific use case", + commentForLevelOfDetail = "Custom level of detail settings" +} = Astro.props; + +const code = `@Composable +fun PerformanceOptimizedMap() { + val mapViewState = remember { HereViewState() } + + LaunchedEffect(mapViewState) { + mapViewState.getMapViewHolder()?.let { holder -> + val mapScene = holder.map + + // ${commentForPerformanceSettings} + mapScene.setLayerVisibility(MapScene.Layers.TRAFFIC_FLOW, VisibilityState.VISIBLE) + + // ${commentForOptimizeUseCase} + val mapSettings = mapScene.mapSettings + mapSettings.isTiltGesturesEnabled = false + mapSettings.isRotateGesturesEnabled = false + + // ${commentForLevelOfDetail} + mapScene.setLevelOfDetail(LevelOfDetail.HIGH) + } + } + + HereMapView(state = mapViewState) { + // Your MapConductor components + } +}`; +--- + + + diff --git a/docs/src/components/core/mapviewholder/SafeNativeAccessExample.astro b/docs/src/components/core/mapviewholder/SafeNativeAccessExample.astro new file mode 100644 index 00000000..827f4256 --- /dev/null +++ b/docs/src/components/core/mapviewholder/SafeNativeAccessExample.astro @@ -0,0 +1,40 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForPolling?: string; + commentForConfigureFeatures?: string; +} + +const { + commentForPolling = "Poll until map is ready", + commentForConfigureFeatures = "Configure native features" +} = Astro.props; + +const code = `@Composable +fun SafeNativeAccess() { + val mapViewState = remember { MapboxViewState() } + var isMapReady by remember { mutableStateOf(false) } + + LaunchedEffect(mapViewState) { + // ${commentForPolling} + while (!isMapReady) { + delay(100) + isMapReady = mapViewState.getMapViewHolder() != null + } + + // Now safe to use native APIs + mapViewState.getMapViewHolder()?.let { holder -> + val mapboxMap = holder.map + // ${commentForConfigureFeatures} + } + } + + MapboxMapView(state = mapViewState) { + // Your MapConductor components + } +}`; +--- + + + diff --git a/docs/src/components/core/mapviewholder/ThirdPartyIntegrationExample.astro b/docs/src/components/core/mapviewholder/ThirdPartyIntegrationExample.astro new file mode 100644 index 00000000..4b9cfbda --- /dev/null +++ b/docs/src/components/core/mapviewholder/ThirdPartyIntegrationExample.astro @@ -0,0 +1,47 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForIntegration?: string; + commentForQueryResults?: string; +} + +const { + commentForIntegration = "Integrate with ArcGIS Online services", + commentForQueryResults = "Process feature query results" +} = Astro.props; + +const code = `@Composable +fun ThirdPartyIntegration() { + val mapViewState = rememberArcGISMapViewState() + + LaunchedEffect(mapViewState) { + mapViewState.getMapViewHolder()?.let { holder -> + val sceneView = holder.map + + // ${commentForIntegration} + val featureTable = ServiceFeatureTable("https://services.arcgis.com/...") + val featureLayer = FeatureLayer(featureTable) + + sceneView.map.basemap.baseLayers.add(featureLayer) + + // Query features + val queryParams = QueryParameters().apply { + whereClause = "STATE_NAME = 'California'" + } + + featureTable.queryFeaturesAsync(queryParams).addDoneListener { + val results = it.result + // ${commentForQueryResults} + } + } + } + + ArcGISMapView(state = mapViewState) { + // Your MapConductor components + } +}`; +--- + + + diff --git a/docs/src/components/core/marker-icons/DebugImageIconExample.astro b/docs/src/components/core/marker-icons/DebugImageIconExample.astro new file mode 100644 index 00000000..65ce627e --- /dev/null +++ b/docs/src/components/core/marker-icons/DebugImageIconExample.astro @@ -0,0 +1,15 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `Marker( + position = position, + icon = ImageDefaultIcon( + drawable = customDrawable, + anchor = Offset(0.5f, 1.0f), + debug = true // Shows anchor point and bounds + ) +)`; +--- + + + diff --git a/docs/src/components/core/marker-icons/DefaultIconSignature.astro b/docs/src/components/core/marker-icons/DefaultIconSignature.astro new file mode 100644 index 00000000..7bdfba62 --- /dev/null +++ b/docs/src/components/core/marker-icons/DefaultIconSignature.astro @@ -0,0 +1,17 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `DefaultMarkerIcon( + scale: Float = 1.0f, + label: String? = null, + fillColor: Color = Color.Red, + strokeColor: Color = Color.Black, + strokeWidth: Dp = 1.dp, + labelTextColor: Color = Color.White, + labelStrokeColor: Color? = null, + debug: Boolean = false +)`; +--- + + + diff --git a/docs/src/components/core/marker-icons/DefaultIconUsageExamples.astro b/docs/src/components/core/marker-icons/DefaultIconUsageExamples.astro new file mode 100644 index 00000000..d804f170 --- /dev/null +++ b/docs/src/components/core/marker-icons/DefaultIconUsageExamples.astro @@ -0,0 +1,46 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `// ${commentForMapViewUsage} +MapView(state = mapViewState) { + // Basic red marker + Marker( + position = GeoPoint.fromLatLong(37.7749, -122.4194), + icon = DefaultMarkerIcon() + ) + + // Custom colored marker with label + Marker( + position = GeoPoint.fromLatLong(37.7849, -122.4094), + icon = DefaultIcon( + scale = 1.2f, + label = "SF", + fillColor = Color.Blue, + strokeColor = Color.White, + strokeWidth = 2.dp + ) + ) + + // Small marker with custom styling + Marker( + position = GeoPoint.fromLatLong(37.7649, -122.4294), + icon = DefaultIcon( + scale = 0.8f, + fillColor = Color.Green, + labelTextColor = Color.Black, + label = "POI" + ) + ) +}`; +--- + + + diff --git a/docs/src/components/core/marker-icons/DrawableDefaultIconSignature.astro b/docs/src/components/core/marker-icons/DrawableDefaultIconSignature.astro new file mode 100644 index 00000000..e41b1949 --- /dev/null +++ b/docs/src/components/core/marker-icons/DrawableDefaultIconSignature.astro @@ -0,0 +1,13 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `DrawableDefaultIcon( + backgroundDrawable: Drawable, + scale: Float = 1.0f, + strokeColor: Color? = null, + strokeWidth: Dp = 1.dp +)`; +--- + + + diff --git a/docs/src/components/core/marker-icons/DrawableIconExamples.astro b/docs/src/components/core/marker-icons/DrawableIconExamples.astro new file mode 100644 index 00000000..64d8b4d2 --- /dev/null +++ b/docs/src/components/core/marker-icons/DrawableIconExamples.astro @@ -0,0 +1,50 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; + commentForCustomDrawable?: string; + commentForCustomBorder?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView", + commentForCustomDrawable = "Custom drawable marker", + commentForCustomBorder = "Drawable with custom border" +} = Astro.props; + +const code = `@Composable +fun DrawableIconExamples() { + val context = LocalContext.current + + // ${commentForMapViewUsage} + MapView(state = mapViewState) { + // ${commentForCustomDrawable} + AppCompatResources.getDrawable(context, R.drawable.custom_marker)?.let { drawable -> + Marker( + position = GeoPoint.fromLatLong(37.7749, -122.4194), + icon = DrawableDefaultIcon( + backgroundDrawable = drawable, + scale = 1.0f + ) + ) + } + + // ${commentForCustomBorder} + AppCompatResources.getDrawable(context, R.drawable.pin_icon)?.let { drawable -> + Marker( + position = GeoPoint.fromLatLong(37.7849, -122.4094), + icon = DrawableDefaultIcon( + backgroundDrawable = drawable, + scale = 1.5f, + strokeColor = Color.Yellow, + strokeWidth = 3.dp + ) + ) + } + } +}`; +--- + + + diff --git a/docs/src/components/core/marker-icons/DynamicIconExample.astro b/docs/src/components/core/marker-icons/DynamicIconExample.astro new file mode 100644 index 00000000..d8f396b6 --- /dev/null +++ b/docs/src/components/core/marker-icons/DynamicIconExample.astro @@ -0,0 +1,45 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `@Composable +fun DynamicIconExample() { + val iconType by remember { mutableStateOf("default") } + val context = LocalContext.current + + // ${commentForMapViewUsage} + MapView(state = mapViewState) { + val icon = when (iconType) { + "default" -> DefaultIcon( + fillColor = Color.Blue, + label = "D" + ) + "drawable" -> AppCompatResources.getDrawable(context, R.drawable.custom_pin)?.let { + DrawableDefaultIcon(backgroundDrawable = it) + } + "image" -> AppCompatResources.getDrawable(context, R.drawable.location_icon)?.let { + ImageDefaultIcon( + drawable = it, + anchor = Offset(0.5f, 1.0f) + ) + } + else -> DefaultIcon() + } + + Marker( + position = GeoPoint.fromLatLong(37.7749, -122.4194), + icon = icon + ) + } +}`; +--- + + + diff --git a/docs/src/components/core/marker-icons/ImageDefaultIconSignature.astro b/docs/src/components/core/marker-icons/ImageDefaultIconSignature.astro new file mode 100644 index 00000000..fd1b4abf --- /dev/null +++ b/docs/src/components/core/marker-icons/ImageDefaultIconSignature.astro @@ -0,0 +1,12 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `ImageDefaultIcon( + drawable: Drawable, + anchor: Offset = Offset(0.5f, 0.5f), + debug: Boolean = false +)`; +--- + + + diff --git a/docs/src/components/core/marker-icons/ImageIconExamples.astro b/docs/src/components/core/marker-icons/ImageIconExamples.astro new file mode 100644 index 00000000..a2a91db2 --- /dev/null +++ b/docs/src/components/core/marker-icons/ImageIconExamples.astro @@ -0,0 +1,50 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; + commentForWeatherStation?: string; + commentForDirectionArrow?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView", + commentForWeatherStation = "Weather station icon with bottom center anchor", + commentForDirectionArrow = "Direction arrow with center anchor" +} = Astro.props; + +const code = `@Composable +fun ImageIconExamples() { + val context = LocalContext.current + + // ${commentForMapViewUsage} + MapView(state = mapViewState) { + // ${commentForWeatherStation} + AppCompatResources.getDrawable(context, R.drawable.weather_station)?.let { icon -> + Marker( + position = GeoPoint.fromLatLong(37.7749, -122.4194), + icon = ImageDefaultIcon( + drawable = icon, + anchor = Offset(0.5f, 1.0f), // Bottom center + debug = false + ) + ) + } + + // ${commentForDirectionArrow} + AppCompatResources.getDrawable(context, R.drawable.direction_arrow)?.let { icon -> + Marker( + position = GeoPoint.fromLatLong(37.7849, -122.4094), + icon = ImageDefaultIcon( + drawable = icon, + anchor = Offset(0.5f, 0.5f), // Center + debug = true // Shows anchor point + ) + ) + } + } +}`; +--- + + + diff --git a/docs/src/components/core/marker-icons/MarkerIconFactoryExample.astro b/docs/src/components/core/marker-icons/MarkerIconFactoryExample.astro new file mode 100644 index 00000000..2c33b942 --- /dev/null +++ b/docs/src/components/core/marker-icons/MarkerIconFactoryExample.astro @@ -0,0 +1,40 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `object MarkerIconFactory { + fun createLocationIcon(color: Color, label: String? = null): MarkerIconInterface { + return DefaultMarkerIcon( + fillColor = color, + strokeColor = Color.White, + strokeWidth = 2.dp, + label = label, + scale = 1.0f + ) + } + + fun createCustomIcon(context: Context, drawableRes: Int, scale: Float = 1.0f): MarkerIconInterface? { + return AppCompatResources.getDrawable(context, drawableRes)?.let { + DrawableDefaultIcon( + backgroundDrawable = it, + scale = scale + ) + } + } + + fun createDirectionalIcon(context: Context, direction: Float): MarkerIconInterface? { + return AppCompatResources.getDrawable(context, R.drawable.arrow)?.let { drawable -> + // Apply rotation to drawable if needed + val rotatedDrawable = drawable.mutate() + rotatedDrawable.setColorFilter(null) + + ImageDefaultIcon( + drawable = rotatedDrawable, + anchor = Offset(0.5f, 0.5f) + ) + } + } +}`; +--- + + + diff --git a/docs/src/components/core/marker-icons/MarkerIconInterface.astro b/docs/src/components/core/marker-icons/MarkerIconInterface.astro new file mode 100644 index 00000000..afbba02a --- /dev/null +++ b/docs/src/components/core/marker-icons/MarkerIconInterface.astro @@ -0,0 +1,10 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `interface MarkerIconInterface { + // Common properties for all marker icon implementations +}`; +--- + + + diff --git a/docs/src/components/core/marker-icons/PerformanceReuseIconsExample.astro b/docs/src/components/core/marker-icons/PerformanceReuseIconsExample.astro new file mode 100644 index 00000000..3965f02d --- /dev/null +++ b/docs/src/components/core/marker-icons/PerformanceReuseIconsExample.astro @@ -0,0 +1,15 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `// Good: Reuse icon instances +val blueIcon = DefaultMarkerIcon(fillColor = Color.Blue) +val redIcon = DefaultMarkerIcon(fillColor = Color.Red) + +markers.forEach { markerData -> + val icon = if (markerData.isSelected) blueIcon else redIcon + Marker(position = markerData.position, icon = icon) +}`; +--- + + + diff --git a/docs/src/components/core/marker-icons/PoiCategoryExample.astro b/docs/src/components/core/marker-icons/PoiCategoryExample.astro new file mode 100644 index 00000000..72acd405 --- /dev/null +++ b/docs/src/components/core/marker-icons/PoiCategoryExample.astro @@ -0,0 +1,13 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `sealed class PoiCategory(val icon: MarkerIconInterface) { + object Restaurant : PoiCategory(DefaultMarkerIcon(fillColor = Color(0xFF4CAF50), label = "🍽️")) + object Hotel : PoiCategory(DefaultMarkerIcon(fillColor = Color(0xFF2196F3), label = "🏨")) + object GasStation : PoiCategory(DefaultMarkerIcon(fillColor = Color(0xFFFF9800), label = "⛽")) + object Hospital : PoiCategory(DefaultMarkerIcon(fillColor = Color(0xFFF44336), label = "🏥")) +}`; +--- + + + diff --git a/docs/src/components/core/marker-icons/StatusIconExample.astro b/docs/src/components/core/marker-icons/StatusIconExample.astro new file mode 100644 index 00000000..a8470c9f --- /dev/null +++ b/docs/src/components/core/marker-icons/StatusIconExample.astro @@ -0,0 +1,20 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `enum class MarkerStatus { ACTIVE, INACTIVE, WARNING, ERROR } + +fun createStatusIcon(status: MarkerStatus): MarkerIconInterface = DefaultMarkerIcon( + fillColor = when (status) { + MarkerStatus.ACTIVE -> Color.Green + MarkerStatus.INACTIVE -> Color.Gray + MarkerStatus.WARNING -> Color.Yellow + MarkerStatus.ERROR -> Color.Red + }, + strokeColor = Color.White, + strokeWidth = 2.dp, + scale = 1.0f +)`; +--- + + + diff --git a/docs/src/components/core/spherical-utilities/ComputeAreaExample.astro b/docs/src/components/core/spherical-utilities/ComputeAreaExample.astro new file mode 100644 index 00000000..52f71678 --- /dev/null +++ b/docs/src/components/core/spherical-utilities/ComputeAreaExample.astro @@ -0,0 +1,24 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `val polygonPoints = listOf( + GeoPoint.fromLatLong(37.7749, -122.4194), + GeoPoint.fromLatLong(37.7849, -122.4094), + GeoPoint.fromLatLong(37.7849, -122.4294), + GeoPoint.fromLatLong(37.7749, -122.4294), + GeoPoint.fromLatLong(37.7749, -122.4194) // Close the polygon +) + +val area = Spherical.computeArea(polygonPoints) +val areaKm2 = area / 1_000_000 // Convert to square kilometers + +println("Polygon area: ${'$'}{areaKm2.toInt()} km²") + +// Signed area tells you orientation +val signedArea = Spherical.computeSignedArea(polygonPoints) +val orientation = if (signedArea > 0) "Counter-clockwise" else "Clockwise" +println("Polygon orientation: ${'$'}orientation")`; +--- + + + diff --git a/docs/src/components/core/spherical-utilities/ComputeAreaSignature.astro b/docs/src/components/core/spherical-utilities/ComputeAreaSignature.astro new file mode 100644 index 00000000..9b731151 --- /dev/null +++ b/docs/src/components/core/spherical-utilities/ComputeAreaSignature.astro @@ -0,0 +1,9 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `fun computeArea(path: List): Double +fun computeSignedArea(path: List): Double`; +--- + + + diff --git a/docs/src/components/core/spherical-utilities/ComputeDistanceBetweenExample.astro b/docs/src/components/core/spherical-utilities/ComputeDistanceBetweenExample.astro new file mode 100644 index 00000000..f887d6d6 --- /dev/null +++ b/docs/src/components/core/spherical-utilities/ComputeDistanceBetweenExample.astro @@ -0,0 +1,31 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForFormulaUsage?: string; + fromLatitude?: number; + fromLongitude?: number; + toLatitude?: number; + toLongitude?: number; +} + +const { + commentForFormulaUsage = "Calculate the shortest distance between two points using the haversine formula", + fromLatitude = 37.7749, + fromLongitude = -122.4194, + toLatitude = 40.7128, + toLongitude = -74.006, +} = Astro.props; + +const code = `val sanFrancisco = GeoPoint.fromLatLong(${fromLatitude}, ${fromLongitude}) +val newYork = GeoPoint.fromLatLong(${toLatitude}, ${toLongitude}) + +val distanceMeters = Spherical.computeDistanceBetween(sanFrancisco, newYork) +val distanceKm = distanceMeters / 1000.0 +val distanceMiles = distanceMeters / 1609.344 + +println("Distance: ${'$'}{distanceKm.toInt()} km (${'$'}{distanceMiles.toInt()} miles)") // ${commentForFormulaUsage}`; +--- + + + diff --git a/docs/src/components/core/spherical-utilities/ComputeDistanceBetweenSignature.astro b/docs/src/components/core/spherical-utilities/ComputeDistanceBetweenSignature.astro new file mode 100644 index 00000000..646d526c --- /dev/null +++ b/docs/src/components/core/spherical-utilities/ComputeDistanceBetweenSignature.astro @@ -0,0 +1,8 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `fun computeDistanceBetween(from: GeoPointInterface, to: GeoPointInterface): Double`; +--- + + + diff --git a/docs/src/components/core/spherical-utilities/ComputeHeadingExample.astro b/docs/src/components/core/spherical-utilities/ComputeHeadingExample.astro new file mode 100644 index 00000000..d6ff032e --- /dev/null +++ b/docs/src/components/core/spherical-utilities/ComputeHeadingExample.astro @@ -0,0 +1,32 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForBearingUsage?: string; +} + +const { + commentForBearingUsage = "Calculate the initial bearing (direction) from one point to another" +} = Astro.props; + +const code = `val start = GeoPoint.fromLatLong(37.7749, -122.4194) +val destination = GeoPoint.fromLatLong(40.7128, -74.0060) + +val bearing = Spherical.computeHeading(start, destination) +println("Head ${'$'}{bearing.toInt()}° from San Francisco to reach New York") // ${commentForBearingUsage} + +// Convert to compass direction +val compassDirection = when { + bearing >= -22.5 && bearing < 22.5 -> "North" + bearing >= 22.5 && bearing < 67.5 -> "Northeast" + bearing >= 67.5 && bearing < 112.5 -> "East" + bearing >= 112.5 && bearing < 157.5 -> "Southeast" + bearing >= 157.5 || bearing < -157.5 -> "South" + bearing >= -157.5 && bearing < -112.5 -> "Southwest" + bearing >= -112.5 && bearing < -67.5 -> "West" + else -> "Northwest" +}`; +--- + + + diff --git a/docs/src/components/core/spherical-utilities/ComputeHeadingSignature.astro b/docs/src/components/core/spherical-utilities/ComputeHeadingSignature.astro new file mode 100644 index 00000000..5f210452 --- /dev/null +++ b/docs/src/components/core/spherical-utilities/ComputeHeadingSignature.astro @@ -0,0 +1,8 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `fun computeHeading(from: GeoPointInterface, to: GeoPointInterface): Double`; +--- + + + diff --git a/docs/src/components/core/spherical-utilities/ComputeLengthExample.astro b/docs/src/components/core/spherical-utilities/ComputeLengthExample.astro new file mode 100644 index 00000000..014af1ce --- /dev/null +++ b/docs/src/components/core/spherical-utilities/ComputeLengthExample.astro @@ -0,0 +1,23 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForRouteDescription?: string; +} + +const { + commentForRouteDescription = "Calculate the total length of a path consisting of multiple points" +} = Astro.props; + +const code = `val routePoints = listOf( + GeoPoint.fromLatLong(37.7749, -122.4194), // San Francisco + GeoPoint.fromLatLong(37.7849, -122.4094), // North Beach + GeoPoint.fromLatLong(37.7949, -122.3994), // Russian Hill + GeoPoint.fromLatLong(37.8049, -122.3894) // Fisherman's Wharf +) + +val totalDistance = Spherical.computeLength(routePoints) +println("Route length: ${'${'}(totalDistance / 1000).toInt()} km") // ${commentForRouteDescription}`; +--- + + diff --git a/docs/src/components/core/spherical-utilities/ComputeLengthSignature.astro b/docs/src/components/core/spherical-utilities/ComputeLengthSignature.astro new file mode 100644 index 00000000..3fffcfcc --- /dev/null +++ b/docs/src/components/core/spherical-utilities/ComputeLengthSignature.astro @@ -0,0 +1,8 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `fun computeLength(path: List): Double`; +--- + + + diff --git a/docs/src/components/core/spherical-utilities/ComputeOffsetExample.astro b/docs/src/components/core/spherical-utilities/ComputeOffsetExample.astro new file mode 100644 index 00000000..428fe4c5 --- /dev/null +++ b/docs/src/components/core/spherical-utilities/ComputeOffsetExample.astro @@ -0,0 +1,17 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `val origin = GeoPoint.fromLatLong(37.7749, -122.4194) + +// Points around the origin +val north1km = Spherical.computeOffset(origin, 1000.0, 0.0) // 1km north +val east1km = Spherical.computeOffset(origin, 1000.0, 90.0) // 1km east +val south1km = Spherical.computeOffset(origin, 1000.0, 180.0) // 1km south +val west1km = Spherical.computeOffset(origin, 1000.0, 270.0) // 1km west + +// Create a square around the origin +val squarePoints = listOf(north1km, east1km, south1km, west1km, north1km)`; +--- + + + diff --git a/docs/src/components/core/spherical-utilities/ComputeOffsetOriginExample.astro b/docs/src/components/core/spherical-utilities/ComputeOffsetOriginExample.astro new file mode 100644 index 00000000..592d600e --- /dev/null +++ b/docs/src/components/core/spherical-utilities/ComputeOffsetOriginExample.astro @@ -0,0 +1,15 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `val destination = GeoPoint.fromLatLong(37.7849, -122.4094) +val distance = 1000.0 // 1km +val originalHeading = 45.0 // Northeast + +val origin = Spherical.computeOffsetOrigin(destination, distance, originalHeading) +origin?.let { point -> + println("Started from: ${'$'}{point.latitude}, ${'$'}{point.longitude}") +}`; +--- + + + diff --git a/docs/src/components/core/spherical-utilities/ComputeOffsetOriginSignature.astro b/docs/src/components/core/spherical-utilities/ComputeOffsetOriginSignature.astro new file mode 100644 index 00000000..9f101d0f --- /dev/null +++ b/docs/src/components/core/spherical-utilities/ComputeOffsetOriginSignature.astro @@ -0,0 +1,8 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `fun computeOffsetOrigin(to: GeoPointInterface, distance: Double, heading: Double): GeoPoint?`; +--- + + + diff --git a/docs/src/components/core/spherical-utilities/ComputeOffsetSignature.astro b/docs/src/components/core/spherical-utilities/ComputeOffsetSignature.astro new file mode 100644 index 00000000..1ed02e5b --- /dev/null +++ b/docs/src/components/core/spherical-utilities/ComputeOffsetSignature.astro @@ -0,0 +1,8 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `fun computeOffset(origin: GeoPointInterface, distance: Double, heading: Double): GeoPoint`; +--- + + + diff --git a/docs/src/components/core/spherical-utilities/GeofenceExample.astro b/docs/src/components/core/spherical-utilities/GeofenceExample.astro new file mode 100644 index 00000000..dedf2650 --- /dev/null +++ b/docs/src/components/core/spherical-utilities/GeofenceExample.astro @@ -0,0 +1,59 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + geofenceRadiusMeters?: number; + commentForMapViewUsage?: string; + labelInside?: string; + labelOutside?: string; +} + +const { + geofenceRadiusMeters = 1000.0, + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView", + labelInside = "Inside", + labelOutside = "Outside" +} = Astro.props; + +const code = `@Composable +fun GeofenceExample() { + val geofenceCenter = GeoPoint.fromLatLong(37.7749, -122.4194) + val geofenceRadius = ${geofenceRadiusMeters} // 1km + + var userLocation by remember { mutableStateOf(null) } + var insideGeofence by remember { mutableStateOf(false) } + + // Check geofence status + LaunchedEffect(userLocation) { + userLocation?.let { location -> + val distance = Spherical.computeDistanceBetween(location, geofenceCenter) + insideGeofence = distance <= geofenceRadius + } + } + + // ${commentForMapViewUsage} + MapView(state = mapViewState) { + // Geofence boundary + Circle( + center = geofenceCenter, + radiusMeters = geofenceRadius, + strokeColor = if (insideGeofence) Color.Green else Color.Red, + strokeWidth = 3.dp, + fillColor = Color.Blue.copy(alpha = 0.1f) + ) + + userLocation?.let { location -> + Marker( + position = location, + icon = DefaultIcon( + fillColor = if (insideGeofence) Color.Green else Color.Red, + label = if (insideGeofence) "${labelInside}" else "${labelOutside}" + ) + ) + } + } +}`; +--- + + + diff --git a/docs/src/components/core/spherical-utilities/InterpolateExample.astro b/docs/src/components/core/spherical-utilities/InterpolateExample.astro new file mode 100644 index 00000000..0b5eba47 --- /dev/null +++ b/docs/src/components/core/spherical-utilities/InterpolateExample.astro @@ -0,0 +1,56 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForWaypoints?: string; + commentForMapViewUsage?: string; +} + +const { + commentForWaypoints = "Create waypoints along the great circle route", + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `val start = GeoPoint.fromLatLong(37.7749, -122.4194) +val end = GeoPoint.fromLatLong(40.7128, -74.0060) + +// ${commentForWaypoints} +val waypoints = (0..10).map { i -> + val fraction = i / 10.0 + Spherical.interpolate(start, end, fraction) +} + +// Use in a route animation +@Composable +fun AnimatedRoute() { + var currentWaypoint by remember { mutableStateOf(0) } + + LaunchedEffect(Unit) { + while (currentWaypoint < waypoints.size - 1) { + delay(1000) + currentWaypoint++ + } + } + + // ${commentForMapViewUsage} + MapView(state = mapViewState) { + // Show route + Polyline( + points = waypoints, + strokeColor = Color.Blue, + strokeWidth = 3.dp + ) + + // Moving marker + if (currentWaypoint < waypoints.size) { + Marker( + position = waypoints[currentWaypoint], + icon = DefaultIcon(fillColor = Color.Red) + ) + } + } +}`; +--- + + + diff --git a/docs/src/components/core/spherical-utilities/InterpolateSignature.astro b/docs/src/components/core/spherical-utilities/InterpolateSignature.astro new file mode 100644 index 00000000..87b9345d --- /dev/null +++ b/docs/src/components/core/spherical-utilities/InterpolateSignature.astro @@ -0,0 +1,8 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `fun interpolate(from: GeoPointInterface, to: GeoPointInterface, fraction: Double): GeoPoint`; +--- + + + diff --git a/docs/src/components/core/spherical-utilities/LinearInterpolateExample.astro b/docs/src/components/core/spherical-utilities/LinearInterpolateExample.astro new file mode 100644 index 00000000..9fd577d0 --- /dev/null +++ b/docs/src/components/core/spherical-utilities/LinearInterpolateExample.astro @@ -0,0 +1,12 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `val start = GeoPoint.fromLatLong(37.7749, -122.4194) +val end = GeoPoint.fromLatLong(37.7849, -122.4094) // Short distance + +// For small distances, linear interpolation is faster and sufficiently accurate +val midpoint = Spherical.linearInterpolate(start, end, 0.5)`; +--- + + + diff --git a/docs/src/components/core/spherical-utilities/LinearInterpolateSignature.astro b/docs/src/components/core/spherical-utilities/LinearInterpolateSignature.astro new file mode 100644 index 00000000..2cf155a8 --- /dev/null +++ b/docs/src/components/core/spherical-utilities/LinearInterpolateSignature.astro @@ -0,0 +1,8 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `fun linearInterpolate(from: GeoPointInterface, to: GeoPointInterface, fraction: Double): GeoPoint`; +--- + + + diff --git a/docs/src/components/core/spherical-utilities/ProximityAlertExample.astro b/docs/src/components/core/spherical-utilities/ProximityAlertExample.astro new file mode 100644 index 00000000..1c087ca5 --- /dev/null +++ b/docs/src/components/core/spherical-utilities/ProximityAlertExample.astro @@ -0,0 +1,73 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForProximity?: string; + commentForMapViewUsage?: string; + alertRadiusMeters?: number; + nearMessage?: string; +} + +const { + commentForProximity = "Update proximity when user location changes", + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView", + alertRadiusMeters = 500.0, + nearMessage = "You are near the target!" +} = Astro.props; + +const code = `@Composable +fun ProximityAlert() { + val targetLocation = GeoPoint.fromLatLong(37.7749, -122.4194) + val alertRadius = ${alertRadiusMeters} // 500 meters + + var userLocation by remember { mutableStateOf(null) } + var isNearTarget by remember { mutableStateOf(false) } + + // ${commentForProximity} + LaunchedEffect(userLocation) { + userLocation?.let { location -> + val distance = Spherical.computeDistanceBetween(location, targetLocation) + isNearTarget = distance <= alertRadius + } + } + + // ${commentForMapViewUsage} + MapView(state = mapViewState) { + // Target location + Marker( + position = targetLocation, + icon = DefaultIcon( + fillColor = if (isNearTarget) Color.Green else Color.Red, + label = "Target" + ) + ) + + // Alert radius + Circle( + center = targetLocation, + radiusMeters = alertRadius, + strokeColor = Color.Blue, + fillColor = Color.Blue.copy(alpha = 0.2f) + ) + + // User location if available + userLocation?.let { location -> + Marker( + position = location, + icon = DefaultIcon(fillColor = Color.Blue, label = "You") + ) + } + } + + if (isNearTarget) { + Text( + text = "${nearMessage}", + color = Color.Green, + fontWeight = FontWeight.Bold + ) + } +}`; +--- + + + diff --git a/docs/src/components/core/spherical-utilities/RouteProgressExample.astro b/docs/src/components/core/spherical-utilities/RouteProgressExample.astro new file mode 100644 index 00000000..3173223c --- /dev/null +++ b/docs/src/components/core/spherical-utilities/RouteProgressExample.astro @@ -0,0 +1,87 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `@Composable +fun RouteProgress() { + val route = listOf( + GeoPoint.fromLatLong(37.7749, -122.4194), + GeoPoint.fromLatLong(37.7849, -122.4094), + GeoPoint.fromLatLong(37.7949, -122.3994) + ) + + var currentPosition by remember { mutableStateOf(route.first()) } + val totalDistance = Spherical.computeLength(route) + + // Calculate progress along route + fun calculateProgress(position: GeoPointInterface): Double { + var distanceToPosition = 0.0 + var minDistanceToRoute = Double.MAX_VALUE + var bestSegmentProgress = 0.0 + + // Find closest point on route + for (i in 0 until route.size - 1) { + val segmentStart = route[i] + val segmentEnd = route[i + 1] + val segmentLength = Spherical.computeDistanceBetween(segmentStart, segmentEnd) + + // Find closest point on this segment + var closestFraction = 0.0 + var minSegmentDistance = Double.MAX_VALUE + + for (fraction in 0..100) { + val testFraction = fraction / 100.0 + val testPoint = Spherical.interpolate(segmentStart, segmentEnd, testFraction) + val distance = Spherical.computeDistanceBetween(position, testPoint) + + if (distance < minSegmentDistance) { + minSegmentDistance = distance + closestFraction = testFraction + } + } + + if (minSegmentDistance < minDistanceToRoute) { + minDistanceToRoute = minSegmentDistance + bestSegmentProgress = distanceToPosition + (segmentLength * closestFraction) + } + + distanceToPosition += segmentLength + } + + return bestSegmentProgress / totalDistance + } + + val progress = calculateProgress(currentPosition) + + Column { + Text("Route Progress: ${'$'}{(progress * 100).toInt()}%") + LinearProgressIndicator(progress = progress.toFloat()) + + // ${commentForMapViewUsage} + MapView(state = mapViewState) { + // Show route + Polyline( + points = route, + strokeColor = Color.Blue, + strokeWidth = 4.dp + ) + + // Current position + Marker( + position = currentPosition, + icon = DefaultIcon(fillColor = Color.Red, label = "Current") + ) + } + } +}`; +--- + + + diff --git a/docs/src/components/core/spherical-utilities/SphericalImportExample.astro b/docs/src/components/core/spherical-utilities/SphericalImportExample.astro new file mode 100644 index 00000000..03f8e465 --- /dev/null +++ b/docs/src/components/core/spherical-utilities/SphericalImportExample.astro @@ -0,0 +1,8 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `import com.mapconductor.core.spherical.Spherical`; +--- + + + diff --git a/docs/src/components/core/zoom-levels/AnimateToZoomExample.astro b/docs/src/components/core/zoom-levels/AnimateToZoomExample.astro new file mode 100644 index 00000000..b5b4bcde --- /dev/null +++ b/docs/src/components/core/zoom-levels/AnimateToZoomExample.astro @@ -0,0 +1,17 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `// Smooth zoom animation +fun animateToZoom(targetZoom: Double) { + val animator = ValueAnimator.ofFloat(currentZoom.toFloat(), targetZoom.toFloat()) + animator.duration = 1000 + animator.addUpdateListener { animation -> + val newZoom = animation.animatedValue as Float + updateCameraPosition(currentPosition.copy(zoom = newZoom.toDouble())) + } + animator.start() +}`; +--- + + + diff --git a/docs/src/components/core/zoom-levels/BuildingScaleExamples.astro b/docs/src/components/core/zoom-levels/BuildingScaleExamples.astro new file mode 100644 index 00000000..5d9ba645 --- /dev/null +++ b/docs/src/components/core/zoom-levels/BuildingScaleExamples.astro @@ -0,0 +1,17 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `// Building and detail level +val buildingLevel = MapCameraPosition( + position = GeoPoint.fromLatLong(37.7749, -122.4194), + zoom = 19.0 // Shows individual buildings +) + +val maximumDetail = MapCameraPosition( + position = GeoPoint.fromLatLong(37.7749, -122.4194), + zoom = 21.0 // Maximum zoom level +)`; +--- + + + diff --git a/docs/src/components/core/zoom-levels/ContentBasedZoomExample.astro b/docs/src/components/core/zoom-levels/ContentBasedZoomExample.astro new file mode 100644 index 00000000..4d757a90 --- /dev/null +++ b/docs/src/components/core/zoom-levels/ContentBasedZoomExample.astro @@ -0,0 +1,66 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForBoundsCalc?: string; + commentForZoomSelection?: string; + commentForMapViewUsage?: string; +} + +const { + commentForBoundsCalc = "Calculate bounds containing all markers", + commentForZoomSelection = "Select appropriate zoom for content", + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `@Composable +fun ContentBasedZoom() { + val markers = remember { + listOf( + GeoPoint.fromLatLong(37.7749, -122.4194), + GeoPoint.fromLatLong(37.7849, -122.4094), + GeoPoint.fromLatLong(37.7949, -122.3994) + ) + } + + // ${commentForBoundsCalc} + val bounds = GeoRectBounds() + markers.forEach { bounds.extend(it) } + + // ${commentForZoomSelection} + val appropriateZoom = when { + bounds.isEmpty -> 15.0 // Default for single point + else -> { + val span = bounds.toSpan() + when { + span?.latitude ?: 0.0 > 10.0 -> 4.0 // Large area + span?.latitude ?: 0.0 > 1.0 -> 8.0 // Medium area + span?.latitude ?: 0.0 > 0.1 -> 12.0 // Small area + span?.latitude ?: 0.0 > 0.01 -> 16.0 // Very small area + else -> 18.0 // Minimal area + } + } + } + + val cameraPosition = MapCameraPosition( + position = bounds.center ?: markers.first(), + zoom = appropriateZoom + ) + + // ${commentForMapViewUsage} + MapView( + state = mapViewState, + cameraPosition = cameraPosition + ) { + markers.forEach { position -> + Marker( + position = position, + icon = DefaultMarkerIcon(fillColor = Color.Blue) + ) + } + } +}`; +--- + + + diff --git a/docs/src/components/core/zoom-levels/ContextAwareZoomExample.astro b/docs/src/components/core/zoom-levels/ContextAwareZoomExample.astro new file mode 100644 index 00000000..fb693dff --- /dev/null +++ b/docs/src/components/core/zoom-levels/ContextAwareZoomExample.astro @@ -0,0 +1,60 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; + userLabel?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView", + userLabel = "You" +} = Astro.props; + +const code = `@Composable +fun ContextAwareZoom() { + val userLocation = GeoPoint.fromLatLong(37.7749, -122.4194) + val searchResults = remember { /* your search results */ } + + // Select zoom based on context + val contextualZoom = when { + searchResults.isEmpty() -> 15.0 // User location focus + searchResults.size == 1 -> 16.0 // Single result + searchResults.size < 5 -> 14.0 // Few results + else -> { + // Calculate appropriate zoom for all results + val bounds = GeoRectBounds() + searchResults.forEach { bounds.extend(it.location) } + calculateZoomForBounds(bounds) + } + } + + val cameraPosition = MapCameraPosition( + position = if (searchResults.isEmpty()) userLocation else bounds.center!!, + zoom = contextualZoom + ) + + // ${commentForMapViewUsage} + MapView( + state = mapViewState, + cameraPosition = cameraPosition + ) { + // User location + Marker( + position = userLocation, + icon = DefaultMarkerIcon(fillColor = Color.Blue, label = "${userLabel}") + ) + + // Search results + searchResults.forEach { result -> + Marker( + position = result.location, + icon = DefaultIcon(fillColor = Color.Red) + ) + } + } +}`; +--- + + + diff --git a/docs/src/components/core/zoom-levels/GlobalScaleExamples.astro b/docs/src/components/core/zoom-levels/GlobalScaleExamples.astro new file mode 100644 index 00000000..748624c0 --- /dev/null +++ b/docs/src/components/core/zoom-levels/GlobalScaleExamples.astro @@ -0,0 +1,17 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `// World and continent level +val worldLevel = MapCameraPosition( + position = GeoPoint.fromLatLong(0.0, 0.0), + zoom = 2.0 // Shows continents and oceans +) + +val continentLevel = MapCameraPosition( + position = GeoPoint.fromLatLong(39.8283, -98.5795), // USA center + zoom = 4.0 // Shows entire continent +)`; +--- + + + diff --git a/docs/src/components/core/zoom-levels/MetropolitanScaleExamples.astro b/docs/src/components/core/zoom-levels/MetropolitanScaleExamples.astro new file mode 100644 index 00000000..3f173b0b --- /dev/null +++ b/docs/src/components/core/zoom-levels/MetropolitanScaleExamples.astro @@ -0,0 +1,17 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `// City and metropolitan area level +val metropolitanLevel = MapCameraPosition( + position = GeoPoint.fromLatLong(37.7749, -122.4194), // San Francisco + zoom = 10.0 // Shows metropolitan area +) + +val cityLevel = MapCameraPosition( + position = GeoPoint.fromLatLong(37.7749, -122.4194), + zoom = 12.0 // Shows city center and suburbs +)`; +--- + + + diff --git a/docs/src/components/core/zoom-levels/NeighborhoodScaleExamples.astro b/docs/src/components/core/zoom-levels/NeighborhoodScaleExamples.astro new file mode 100644 index 00000000..9794941d --- /dev/null +++ b/docs/src/components/core/zoom-levels/NeighborhoodScaleExamples.astro @@ -0,0 +1,17 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `// District and neighborhood level +val districtLevel = MapCameraPosition( + position = GeoPoint.fromLatLong(37.7749, -122.4194), + zoom = 13.0 // Shows districts +) + +val neighborhoodLevel = MapCameraPosition( + position = GeoPoint.fromLatLong(37.7749, -122.4194), + zoom = 15.0 // Shows neighborhoods and major streets +)`; +--- + + + diff --git a/docs/src/components/core/zoom-levels/PerformanceAdaptiveZoomExample.astro b/docs/src/components/core/zoom-levels/PerformanceAdaptiveZoomExample.astro new file mode 100644 index 00000000..e886f222 --- /dev/null +++ b/docs/src/components/core/zoom-levels/PerformanceAdaptiveZoomExample.astro @@ -0,0 +1,66 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `@Composable +fun PerformanceAdaptiveZoom() { + val markerCount = 1000 + var displayedMarkers by remember { mutableStateOf>(emptyList()) } + + val cameraPosition = MapCameraPosition( + position = GeoPoint.fromLatLong(37.7749, -122.4194), + zoom = 12.0 + ) + + LaunchedEffect(cameraPosition) { + // Adapt marker display based on zoom level + displayedMarkers = when { + cameraPosition.zoom < 8.0 -> { + // Very low zoom: show only major markers + allMarkers.filter { it.importance > 0.8 } + } + cameraPosition.zoom < 12.0 -> { + // Medium zoom: show important markers + allMarkers.filter { it.importance > 0.5 } + } + cameraPosition.zoom < 16.0 -> { + // High zoom: show most markers + allMarkers.filter { it.importance > 0.2 } + } + else -> { + // Maximum zoom: show all markers + allMarkers + } + } + } + + // ${commentForMapViewUsage} + MapView( + state = mapViewState, + cameraPosition = cameraPosition + ) { + displayedMarkers.forEach { marker -> + Marker( + position = marker, + icon = DefaultMarkerIcon( + scale = when { + cameraPosition.zoom < 10.0 -> 1.2f + cameraPosition.zoom < 15.0 -> 1.0f + else -> 0.8f + } + ) + ) + } + } +}`; +--- + + + diff --git a/docs/src/components/core/zoom-levels/RegionalScaleExamples.astro b/docs/src/components/core/zoom-levels/RegionalScaleExamples.astro new file mode 100644 index 00000000..4aef5f1c --- /dev/null +++ b/docs/src/components/core/zoom-levels/RegionalScaleExamples.astro @@ -0,0 +1,17 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `// Country and state level +val countryLevel = MapCameraPosition( + position = GeoPoint.fromLatLong(39.8283, -98.5795), + zoom = 6.0 // Shows entire country +) + +val stateLevel = MapCameraPosition( + position = GeoPoint.fromLatLong(36.7783, -119.4179), // California center + zoom = 8.0 // Shows state or large region +)`; +--- + + + diff --git a/docs/src/components/core/zoom-levels/ResponsiveZoomExample.astro b/docs/src/components/core/zoom-levels/ResponsiveZoomExample.astro new file mode 100644 index 00000000..f1828e24 --- /dev/null +++ b/docs/src/components/core/zoom-levels/ResponsiveZoomExample.astro @@ -0,0 +1,34 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `@Composable +fun ResponsiveZoom() { + val configuration = LocalConfiguration.current + val isTablet = configuration.screenWidthDp >= 600 + + // Adjust zoom for screen size + val baseZoom = if (isTablet) 14.0 else 16.0 + + // ${commentForMapViewUsage} + MapView( + state = mapViewState, + cameraPosition = MapCameraPosition( + position = center, + zoom = baseZoom + ) + ) { + // Content + } +}`; +--- + + + diff --git a/docs/src/components/core/zoom-levels/StreetScaleExamples.astro b/docs/src/components/core/zoom-levels/StreetScaleExamples.astro new file mode 100644 index 00000000..943491b8 --- /dev/null +++ b/docs/src/components/core/zoom-levels/StreetScaleExamples.astro @@ -0,0 +1,17 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `// Street and block level +val streetLevel = MapCameraPosition( + position = GeoPoint.fromLatLong(37.7749, -122.4194), + zoom = 16.0 // Shows street layout +) + +val detailedStreetLevel = MapCameraPosition( + position = GeoPoint.fromLatLong(37.7749, -122.4194), + zoom = 18.0 // Shows individual streets and small buildings +)`; +--- + + + diff --git a/docs/src/components/core/zoom-levels/ZoomControlsExample.astro b/docs/src/components/core/zoom-levels/ZoomControlsExample.astro new file mode 100644 index 00000000..f00bd9e6 --- /dev/null +++ b/docs/src/components/core/zoom-levels/ZoomControlsExample.astro @@ -0,0 +1,69 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; + labelCity?: string; + labelStreet?: string; + labelBuilding?: string; + labelZoomLevel?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView", + labelCity = "City", + labelStreet = "Street", + labelBuilding = "Building", + labelZoomLevel = "Zoom Level" +} = Astro.props; + +const code = `@Composable +fun ZoomControls() { + var currentZoom by remember { mutableStateOf(15.0) } + val center = GeoPoint.fromLatLong(37.7749, -122.4194) + + Column { + // Zoom level display + Text("${labelZoomLevel}: ${'$'}{String.format("%.1f", currentZoom)}") + + // Zoom controls + Row { + Button( + onClick = { currentZoom = (currentZoom + 1).coerceAtMost(21.0) } + ) { + Text("+") + } + + Button( + onClick = { currentZoom = (currentZoom - 1).coerceAtLeast(0.0) } + ) { + Text("-") + } + } + + // Preset zoom buttons + Row { + Button(onClick = { currentZoom = 12.0 }) { Text("${labelCity}") } + Button(onClick = { currentZoom = 15.0 }) { Text("${labelStreet}") } + Button(onClick = { currentZoom = 18.0 }) { Text("${labelBuilding}") } + } + + // ${commentForMapViewUsage} + MapView( + state = mapViewState, + cameraPosition = MapCameraPosition( + position = center, + zoom = currentZoom + ) + ) { + Marker( + position = center, + icon = DefaultMarkerIcon(fillColor = Color.Red) + ) + } + } +}`; +--- + + + diff --git a/docs/src/components/core/zoom-levels/ZoomLevelExamples.astro b/docs/src/components/core/zoom-levels/ZoomLevelExamples.astro new file mode 100644 index 00000000..77392765 --- /dev/null +++ b/docs/src/components/core/zoom-levels/ZoomLevelExamples.astro @@ -0,0 +1,13 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `// Examples of different zoom levels +val worldView = 2.0 // See continents +val countryView = 6.0 // See entire countries +val cityView = 10.0 // See cities +val streetView = 15.0 // See streets +val buildingView = 18.0 // See individual buildings`; +--- + + + diff --git a/docs/src/components/core/zoom-levels/ZoomLevelTesterExample.astro b/docs/src/components/core/zoom-levels/ZoomLevelTesterExample.astro new file mode 100644 index 00000000..f4eeed4f --- /dev/null +++ b/docs/src/components/core/zoom-levels/ZoomLevelTesterExample.astro @@ -0,0 +1,50 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; + labelTestingZoom?: string; + labelNextZoom?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView", + labelTestingZoom = "Testing Zoom Level", + labelNextZoom = "Next Zoom Level" +} = Astro.props; + +const code = `@Composable +fun ZoomLevelTester() { + val testZoomLevels = listOf(0.0, 5.0, 10.0, 15.0, 20.0) + var currentTestIndex by remember { mutableStateOf(0) } + + Column { + Text("${labelTestingZoom}: ${'$'}{testZoomLevels[currentTestIndex]}") + + Button( + onClick = { + currentTestIndex = (currentTestIndex + 1) % testZoomLevels.size + } + ) { + Text("${labelNextZoom}") + } + + // ${commentForMapViewUsage} + MapView( + state = mapViewState, + cameraPosition = MapCameraPosition( + position = GeoPoint.fromLatLong(37.7749, -122.4194), + zoom = testZoomLevels[currentTestIndex] + ) + ) { + Marker( + position = GeoPoint.fromLatLong(37.7749, -122.4194), + icon = DefaultMarkerIcon(fillColor = Color.Red) + ) + } + } +}`; +--- + + + diff --git a/docs/src/components/event/OnMapLoaded.astro b/docs/src/components/event/OnMapLoaded.astro new file mode 100644 index 00000000..2baeb0cf --- /dev/null +++ b/docs/src/components/event/OnMapLoaded.astro @@ -0,0 +1,7 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `typealias OnMapLoadedHandler = (MapViewStateInterface<*>) -> Unit`; +--- + + diff --git a/docs/src/components/examples/advanced-usage/AdvancedMapExample.astro b/docs/src/components/examples/advanced-usage/AdvancedMapExample.astro new file mode 100644 index 00000000..8368f7bb --- /dev/null +++ b/docs/src/components/examples/advanced-usage/AdvancedMapExample.astro @@ -0,0 +1,87 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + centerLat?: number; + centerLong?: number; + zoom?: number; + markerLabel?: string; + commentForMarkerClick?: string; + circleRadiusMeters?: number; + circleStrokeColor?: string; + circleFillColor?: string; + polylinePoints?: Array<{lat: number, long: number}>; + polylineStrokeColor?: string; + polylineStrokeWidth?: string; + commentMarker?: string; + commentCircle?: string; + commentPolyline?: string; +} + +const { + centerLat = 37.7749, + centerLong = -122.4194, + zoom = 15.0, + markerLabel = "Center", + commentForMarkerClick = "Marker: ${markerState.extra}", + circleRadiusMeters = 1000.0, + circleStrokeColor = "Color.Blue", + circleFillColor = "Color.Blue.copy(alpha = 0.3f)", + polylinePoints = [ + {lat: 37.7749, long: -122.4194}, + {lat: 37.7849, long: -122.4094}, + ], + polylineStrokeColor = "", + polylineStrokeWidth = "", + commentMarker = "Marker", + commentCircle = "Circle", + commentPolyline = "Polyline" +} = Astro.props; + +const polylinePointsStr = polylinePoints + .map(p => ` GeoPoint.fromLatLong(${p.lat}, ${p.long})`) + .join(',\n'); + +const polylineStyleStr = polylineStrokeColor || polylineStrokeWidth + ? `,\n${polylineStrokeColor ? ` strokeColor = ${polylineStrokeColor}` : ''}${polylineStrokeColor && polylineStrokeWidth ? ',\n' : ''}${polylineStrokeWidth ? ` strokeWidth = ${polylineStrokeWidth}` : ''}` + : ''; + +const code = `@Composable +fun AdvancedMapScreen() { + val camera = MapCameraPosition( + position = GeoPoint.fromLatLong(${centerLat}, ${centerLong}), + zoom = ${zoom} + ) + val mapViewState = rememberGoogleMapViewState(cameraPosition = camera) + + GoogleMapView( + state = mapViewState + ) { + // ${commentMarker} + Marker( + position = GeoPoint.fromLatLong(${centerLat}, ${centerLong}), + icon = DefaultIcon(label = "${markerLabel}"), + onClick = { markerState -> + println("${commentForMarkerClick}") + } + ) + + // ${commentCircle} + Circle( + center = GeoPoint.fromLatLong(${centerLat}, ${centerLong}), + radiusMeters = ${circleRadiusMeters}, + strokeColor = ${circleStrokeColor}, + fillColor = ${circleFillColor} + ) + + // ${commentPolyline} + Polyline( + points = listOf( +${polylinePointsStr} + )${polylineStyleStr} + ) + } +}`; +--- + + diff --git a/docs/src/components/examples/basic-usage/ClickToAddMarkersExample.astro b/docs/src/components/examples/basic-usage/ClickToAddMarkersExample.astro new file mode 100644 index 00000000..6bedeb93 --- /dev/null +++ b/docs/src/components/examples/basic-usage/ClickToAddMarkersExample.astro @@ -0,0 +1,48 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapView?: string; + commentForRemoveMarker?: string; + markerLabelPrefix?: string; + fillColor?: string; +} + +const { + commentForMapView = "GoogleMapView、MapboxMapView など、選択した地図SDKに置き換えてください", + commentForRemoveMarker = "クリックされたマーカーを削除", + markerLabelPrefix = "Marker", + fillColor = "Color.Blue" +} = Astro.props; + +const code = `@Composable +fun ClickToAddMarkersExample() { + var markers by remember { mutableStateOf>(emptyList()) } + + // ${commentForMapView} + MapView( + state = mapViewState, + onMapClick = { geoPoint -> + val newMarker = MarkerState( + position = geoPoint, + icon = DefaultIcon( + label = "\${markers.size + 1}", + fillColor = ${fillColor} + ), + extra = "${markerLabelPrefix} \${markers.size + 1}", + onClick = { markerState -> + // ${commentForRemoveMarker} + markers = markers.filter { it.id != markerState.id } + } + ) + markers = markers + newMarker + } + ) { + markers.forEach { marker -> + Marker(marker) + } + } +}`; +--- + + diff --git a/docs/src/components/examples/basic-usage/SimpleMapExampleTabs.astro b/docs/src/components/examples/basic-usage/SimpleMapExampleTabs.astro new file mode 100644 index 00000000..4078004b --- /dev/null +++ b/docs/src/components/examples/basic-usage/SimpleMapExampleTabs.astro @@ -0,0 +1,147 @@ +--- +import { Code, Tabs, TabItem } from '@astrojs/starlight/components'; + +interface Props { + googleMapsLat?: number; + googleMapsLong?: number; + googleMapsLabel?: string; + googleMapsExtra?: string; + googleMapsImage?: string; + mapboxLat?: number; + mapboxLong?: number; + mapboxLabel?: string; + mapboxExtra?: string; + mapboxImage?: string; + hereLat?: number; + hereLong?: number; + hereLabel?: string; + hereExtra?: string; + hereImage?: string; + arcgisLat?: number; + arcgisLong?: number; + arcgisLabel?: string; + arcgisExtra?: string; + arcgisImage?: string; + maplibreLat?: number; + maplibreLong?: number; + maplibreLabel?: string; + maplibreExtra?: string; + maplibreImage?: string; +} + +const { + googleMapsLat = 37.7749, + googleMapsLong = -122.4194, + googleMapsLabel = "SF", + googleMapsExtra = "San Francisco", + googleMapsImage = "~/assets/examples/basic-googlemaps.jpg", + mapboxLat = 38.911254, + mapboxLong = -77.033458, + mapboxLabel = "WA", + mapboxExtra = "San Francisco", + mapboxImage = "~/assets/examples/basic-mapbox.jpg", + hereLat = 51.43901, + hereLong = 5.47191, + hereLabel = "EIN", + hereExtra = "San Francisco", + hereImage = "~/assets/examples/basic-here.jpg", + arcgisLat = 37.7749, + arcgisLong = -122.4194, + arcgisLabel = "SF", + arcgisExtra = "San Francisco", + arcgisImage = "~/assets/examples/basic-arcgis.jpg", + maplibreLat = 37.7749, + maplibreLong = -122.4194, + maplibreLabel = "SF", + maplibreExtra = "San Francisco", + maplibreImage = "~/assets/examples/basic-maplibre.jpg", +} = Astro.props; + +const googleMapsCode = `@Composable +fun SimpleMapExample() { + val mapViewState = rememberGoogleMapViewState() + + GoogleMapView(state = mapViewState) { + Marker( + position = GeoPoint.fromLatLong(${googleMapsLat}, ${googleMapsLong}), + icon = DefaultIcon(label = "${googleMapsLabel}"), + extra = "${googleMapsExtra}" + ) + } +}`; + +const mapboxCode = `@Composable +fun SimpleMapExample() { + val mapViewState = rememberMapboxMapViewState() + + MapboxMapView(state = mapViewState) { + Marker( + position = GeoPoint.fromLatLong(${mapboxLat}, ${mapboxLong}), + icon = DefaultIcon(label = "${mapboxLabel}"), + extra = "${mapboxExtra}" + ) + } +}`; + +const hereCode = `@Composable +fun SimpleMapExample() { + val mapViewState = rememberHereMapViewState() + + HereMapView(state = mapViewState) { + Marker( + position = GeoPoint.fromLatLong(${hereLat}, ${hereLong}), + icon = DefaultIcon(label = "${hereLabel}"), + extra = "${hereExtra}" + ) + } +}`; + +const arcgisCode = `@Composable +fun SimpleMapExample() { + val mapViewState = rememberArcGISViewState() + + ArcGISMapView(state = mapViewState) { + Marker( + position = GeoPoint.fromLatLong(${arcgisLat}, ${arcgisLong}), + icon = DefaultIcon(label = "${arcgisLabel}"), + extra = "${arcgisExtra}" + ) + } +}`; + +const maplibreCode = `@Composable +fun SimpleMapExample() { + val mapViewState = rememberMapLibreMapViewState() + + MapLibreMapView(state = mapViewState) { + Marker( + position = GeoPoint.fromLatLong(${maplibreLat}, ${maplibreLong}), + icon = DefaultIcon(label = "${maplibreLabel}"), + extra = "${maplibreExtra}" + ) + } +}`; +--- + + + + +![実行結果]({googleMapsImage}) + + + +![実行結果]({mapboxImage}) + + + +![実行結果]({hereImage}) + + + +![実行結果]({arcgisImage}) + + + +![実行結果]({maplibreImage}) + + diff --git a/docs/src/components/experimental/icons/AnchorPointsExample.astro b/docs/src/components/experimental/icons/AnchorPointsExample.astro new file mode 100644 index 00000000..04c226e4 --- /dev/null +++ b/docs/src/components/experimental/icons/AnchorPointsExample.astro @@ -0,0 +1,9 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `// CircleIcon: anchored at left-center (0.0, 0.5) +// FlagIcon: anchored near the base of the pole (0.176, 0.91)`; +--- + + + diff --git a/docs/src/components/experimental/icons/AnimatedIconExampleComposable.astro b/docs/src/components/experimental/icons/AnimatedIconExampleComposable.astro new file mode 100644 index 00000000..a8a4117b --- /dev/null +++ b/docs/src/components/experimental/icons/AnimatedIconExampleComposable.astro @@ -0,0 +1,62 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `@Composable +fun AnimatedIconExample() { + var scale by remember { mutableStateOf(1.0f) } + var color by remember { mutableStateOf(Color.Red) } + + // Animate scale + LaunchedEffect(Unit) { + while (true) { + animate( + initialValue = 1.0f, + targetValue = 1.5f, + animationSpec = tween(1000) + ) { value, _ -> scale = value } + + animate( + initialValue = 1.5f, + targetValue = 1.0f, + animationSpec = tween(1000) + ) { value, _ -> scale = value } + } + } + + // Animate color + LaunchedEffect(Unit) { + val colors = listOf(Color.Red, Color.Blue, Color.Green, Color.Yellow) + var index = 0 + while (true) { + delay(2000) + index = (index + 1) % colors.size + color = colors[index] + } + } + + val animatedIcon = CircleIcon( + fillColor = color, + strokeColor = Color.White, + scale = scale + ) + + // ${commentForMapViewUsage} + MapView(state = mapViewState) { + Marker( + position = GeoPoint.fromLatLong(37.7749, -122.4194), + icon = animatedIcon + ) + } +}`; +--- + + + diff --git a/docs/src/components/experimental/icons/BasicIconExampleComposable.astro b/docs/src/components/experimental/icons/BasicIconExampleComposable.astro new file mode 100644 index 00000000..ad4bcbee --- /dev/null +++ b/docs/src/components/experimental/icons/BasicIconExampleComposable.astro @@ -0,0 +1,40 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `@Composable +fun BasicIconExample() { + val circleIcon = CircleIcon( + fillColor = Color.Blue, + strokeColor = Color.White + ) + + val flagIcon = FlagIcon( + fillColor = Color.Red, + strokeColor = Color.Black + ) + + // ${commentForMapViewUsage} + MapView(state = mapViewState) { + Marker( + position = GeoPoint.fromLatLong(37.7749, -122.4194), + icon = circleIcon + ) + + Marker( + position = GeoPoint.fromLatLong(37.7849, -122.4094), + icon = flagIcon + ) + } +}`; +--- + + + diff --git a/docs/src/components/experimental/icons/BitmapCachingExample.astro b/docs/src/components/experimental/icons/BitmapCachingExample.astro new file mode 100644 index 00000000..ee42fd19 --- /dev/null +++ b/docs/src/components/experimental/icons/BitmapCachingExample.astro @@ -0,0 +1,13 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `// These will share the same cached bitmap +val icon1 = CircleIcon(fillColor = Color.Red, strokeColor = Color.White) +val icon2 = CircleIcon(fillColor = Color.Red, strokeColor = Color.White) + +// This will create a new cached bitmap +val icon3 = CircleIcon(fillColor = Color.Blue, strokeColor = Color.White)`; +--- + + + diff --git a/docs/src/components/experimental/icons/CategoryIconExampleComposable.astro b/docs/src/components/experimental/icons/CategoryIconExampleComposable.astro new file mode 100644 index 00000000..8af18347 --- /dev/null +++ b/docs/src/components/experimental/icons/CategoryIconExampleComposable.astro @@ -0,0 +1,47 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `@Composable +fun CategoryIconExample() { + data class POI( + val name: String, + val category: String, + val position: GeoPointInterface + ) : java.io.Serializable + + val pois = listOf( + POI("Restaurant", "food", GeoPoint.fromLatLong(37.7749, -122.4194)), + POI("Hotel", "lodging", GeoPoint.fromLatLong(37.7849, -122.4094)), + POI("Gas Station", "fuel", GeoPoint.fromLatLong(37.7649, -122.4294)) + ) + + fun getIconForCategory(category: String) = when (category) { + "food" -> CircleIcon(fillColor = Color.Red, strokeColor = Color.White) + "lodging" -> FlagIcon(fillColor = Color.Blue, strokeColor = Color.White) + "fuel" -> CircleIcon(fillColor = Color.Yellow, strokeColor = Color.Black) + else -> CircleIcon(fillColor = Color.Gray, strokeColor = Color.White) + } + + // ${commentForMapViewUsage} + MapView(state = mapViewState) { + pois.forEach { poi -> + Marker( + position = poi.position, + icon = getIconForCategory(poi.category), + extra = poi.name + ) + } + } +}`; +--- + + + diff --git a/docs/src/components/experimental/icons/CircleIconUsage.astro b/docs/src/components/experimental/icons/CircleIconUsage.astro new file mode 100644 index 00000000..e1ae2c38 --- /dev/null +++ b/docs/src/components/experimental/icons/CircleIconUsage.astro @@ -0,0 +1,20 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `import com.mapconductor.icons.CircleIcon + +// Basic circle icon +val basicCircle = CircleIcon() + +// Customized circle icon +val customCircle = CircleIcon( + fillColor = Color.Blue, + strokeColor = Color.White, + strokeWidth = 2.dp, + scale = 1.2f, + iconSize = 32.dp +)`; +--- + + + diff --git a/docs/src/components/experimental/icons/CustomIconClassExample.astro b/docs/src/components/experimental/icons/CustomIconClassExample.astro new file mode 100644 index 00000000..50bedf08 --- /dev/null +++ b/docs/src/components/experimental/icons/CustomIconClassExample.astro @@ -0,0 +1,43 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `class CustomIcon( + private val fillColor: Color = Color.Blue, + override val scale: Float = 1.0f, + override val iconSize: Dp = 32.dp, + override val debug: Boolean = false +) : AbstractMarkerIcon() { + + override val anchor: Offset = Offset(0.5f, 0.5f) + override val infoAnchor: Offset = Offset(0.5f, 0.0f) + + override fun toBitmapIcon(): BitmapIcon { + val id = "custom_icon_${'$'}{hashCode()}".hashCode() + BitmapIconCache.get(id)?.let { return it } + + val canvasSize = ResourceProvider.dpToPx(iconSize.value * scale) + val bitmap = createBitmap(canvasSize.toInt(), canvasSize.toInt()) + val canvas = Canvas(bitmap) + + // Custom drawing code here + val paint = Paint().apply { + color = fillColor.toArgb() + style = Paint.Style.FILL + isAntiAlias = true + } + + canvas.drawRect(0f, 0f, canvasSize.toFloat(), canvasSize.toFloat(), paint) + + val result = BitmapIcon( + bitmap = bitmap, + anchor = anchor, + size = Size(canvasSize.toFloat(), canvasSize.toFloat()) + ) + BitmapIconCache.put(id, result) + return result + } +}`; +--- + + + diff --git a/docs/src/components/experimental/icons/DebugIconExampleComposable.astro b/docs/src/components/experimental/icons/DebugIconExampleComposable.astro new file mode 100644 index 00000000..5eee7b02 --- /dev/null +++ b/docs/src/components/experimental/icons/DebugIconExampleComposable.astro @@ -0,0 +1,31 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `@Composable +fun DebugIconExample() { + val debugIcon = CircleIcon( + fillColor = Color.Red, + strokeColor = Color.White, + debug = true // Show debug outline and crosshairs + ) + + // ${commentForMapViewUsage} + MapView(state = mapViewState) { + Marker( + position = GeoPoint.fromLatLong(37.7749, -122.4194), + icon = debugIcon + ) + } +}`; +--- + + + diff --git a/docs/src/components/experimental/icons/DynamicIconExampleComposable.astro b/docs/src/components/experimental/icons/DynamicIconExampleComposable.astro new file mode 100644 index 00000000..c961a2f0 --- /dev/null +++ b/docs/src/components/experimental/icons/DynamicIconExampleComposable.astro @@ -0,0 +1,55 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; + commentForColorPicker?: string; + commentForSizeSlider?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView", + commentForColorPicker = "Color picker", + commentForSizeSlider = "Size slider" +} = Astro.props; + +const code = `@Composable +fun DynamicIconExample() { + var iconColor by remember { mutableStateOf(Color.Red) } + var iconSize by remember { mutableStateOf(32.dp) } + + val dynamicIcon = CircleIcon( + fillColor = iconColor, + strokeColor = Color.White, + iconSize = iconSize + ) + + Column { + // ${commentForColorPicker} + Row { + Button(onClick = { iconColor = Color.Red }) { Text("Red") } + Button(onClick = { iconColor = Color.Blue }) { Text("Blue") } + Button(onClick = { iconColor = Color.Green }) { Text("Green") } + } + + // ${commentForSizeSlider} + Slider( + value = iconSize.value, + onValueChange = { iconSize = it.dp }, + valueRange = 16f..64f + ) + Text("Size: ${'$'}{iconSize.value.toInt()}dp") + + // ${commentForMapViewUsage} + MapView(state = mapViewState) { + Marker( + position = GeoPoint.fromLatLong(37.7749, -122.4194), + icon = dynamicIcon + ) + } + } +}`; +--- + + + diff --git a/docs/src/components/experimental/icons/FlagIconUsage.astro b/docs/src/components/experimental/icons/FlagIconUsage.astro new file mode 100644 index 00000000..297f84f7 --- /dev/null +++ b/docs/src/components/experimental/icons/FlagIconUsage.astro @@ -0,0 +1,20 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `import com.mapconductor.icons.FlagIcon + +// Basic flag icon +val basicFlag = FlagIcon() + +// Customized flag icon +val customFlag = FlagIcon( + fillColor = Color.Green, + strokeColor = Color.Black, + strokeWidth = 1.5.dp, + scale = 1.0f, + iconSize = 40.dp +)`; +--- + + + diff --git a/docs/src/components/experimental/icons/IconThemeDefinition.astro b/docs/src/components/experimental/icons/IconThemeDefinition.astro new file mode 100644 index 00000000..dd1de67e --- /dev/null +++ b/docs/src/components/experimental/icons/IconThemeDefinition.astro @@ -0,0 +1,29 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `object IconTheme { + data class Theme( + val primaryColor: Color, + val secondaryColor: Color, + val strokeColor: Color, + val strokeWidth: Dp + ) : java.io.Serializable + + val light = Theme( + primaryColor = Color(0xFF2196F3), + secondaryColor = Color(0xFFFFFFFF), + strokeColor = Color(0xFF000000), + strokeWidth = 1.dp + ) + + val dark = Theme( + primaryColor = Color(0xFF1976D2), + secondaryColor = Color(0xFF424242), + strokeColor = Color(0xFFFFFFFF), + strokeWidth = 1.dp + ) +}`; +--- + + + diff --git a/docs/src/components/experimental/icons/IconsGradleDependencies.astro b/docs/src/components/experimental/icons/IconsGradleDependencies.astro new file mode 100644 index 00000000..cca936e6 --- /dev/null +++ b/docs/src/components/experimental/icons/IconsGradleDependencies.astro @@ -0,0 +1,32 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForBom?: string; + commentForCore?: string; + commentForChooseProvider?: string; + bomVersionPlaceholder?: string; +} + +const { + commentForBom = "Required: Bom module", + commentForCore = "Required: Core module", + commentForChooseProvider = "Choose your map provider", + bomVersionPlaceholder = "$version" +} = Astro.props; + +const code = `dependencies { + implementation "com.mapconductor:mapconductor-icons" + + // ${commentForBom} + implementation "com.mapconductor:mapconductor-bom:${bomVersionPlaceholder}" + // ${commentForCore} + implementation "com.mapconductor:core" + + // ${commentForChooseProvider} + implementation "com.mapconductor:for-googlemaps" +}`; +--- + + + diff --git a/docs/src/components/experimental/icons/InfoWindowAnchorsExample.astro b/docs/src/components/experimental/icons/InfoWindowAnchorsExample.astro new file mode 100644 index 00000000..fd491e5b --- /dev/null +++ b/docs/src/components/experimental/icons/InfoWindowAnchorsExample.astro @@ -0,0 +1,9 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `// CircleIcon info window anchor: center of the circle (0.5, 0.5) +// FlagIcon info window anchor: top of the flag (0.5, 0.0)`; +--- + + + diff --git a/docs/src/components/experimental/icons/ThemedIconExampleComposable.astro b/docs/src/components/experimental/icons/ThemedIconExampleComposable.astro new file mode 100644 index 00000000..97b7435a --- /dev/null +++ b/docs/src/components/experimental/icons/ThemedIconExampleComposable.astro @@ -0,0 +1,45 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `@Composable +fun ThemedIconExample() { + val isDarkTheme = isSystemInDarkTheme() + val theme = if (isDarkTheme) IconTheme.dark else IconTheme.light + + val themedCircle = CircleIcon( + fillColor = theme.primaryColor, + strokeColor = theme.strokeColor, + strokeWidth = theme.strokeWidth + ) + + val themedFlag = FlagIcon( + fillColor = theme.primaryColor, + strokeColor = theme.strokeColor, + strokeWidth = theme.strokeWidth + ) + + // ${commentForMapViewUsage} + MapView(state = mapViewState) { + Marker( + position = GeoPoint.fromLatLong(37.7749, -122.4194), + icon = themedCircle + ) + + Marker( + position = GeoPoint.fromLatLong(37.7849, -122.4094), + icon = themedFlag + ) + } +}`; +--- + + + diff --git a/docs/src/components/experimental/marker-native-strategy/BasicNativeExampleComposable.astro b/docs/src/components/experimental/marker-native-strategy/BasicNativeExampleComposable.astro new file mode 100644 index 00000000..18519761 --- /dev/null +++ b/docs/src/components/experimental/marker-native-strategy/BasicNativeExampleComposable.astro @@ -0,0 +1,53 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; + datasetComment?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView", + datasetComment = "10,000+ markers" +} = Astro.props; + +const code = `@Composable +fun BasicNativeExample() { + // Create native marker manager + val nativeManager = remember { + NativeMarkerManager( + hexGeocell = HexGeocell.defaultGeocell() + ) + } + + // Add markers to native manager + LaunchedEffect(Unit) { + val markers = generateLargeMarkerDataset() // ${datasetComment} + markers.forEach { markerData -> + val entity = MarkerEntityInterface( + state = MarkerState( + id = markerData.id, + position = markerData.position, + icon = DefaultIcon() + ) + ) + nativeManager.registerEntity(entity) + } + } + + // ${commentForMapViewUsage} + MapView(state = mapViewState) { + // Markers are managed by native strategy + // No need to manually add Marker composables + } + + DisposableEffect(Unit) { + onDispose { + nativeManager.destroy() // Important: cleanup native resources + } + } +}`; +--- + + + diff --git a/docs/src/components/experimental/marker-native-strategy/DynamicNativeLoadingExampleComposable.astro b/docs/src/components/experimental/marker-native-strategy/DynamicNativeLoadingExampleComposable.astro new file mode 100644 index 00000000..9d73de2d --- /dev/null +++ b/docs/src/components/experimental/marker-native-strategy/DynamicNativeLoadingExampleComposable.astro @@ -0,0 +1,50 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; + visibleCountLabel?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView", + visibleCountLabel = "Visible Markers" +} = Astro.props; + +const code = `@Composable +fun DynamicNativeLoadingExample() { + val nativeManager = remember { + NativeMarkerManager( + hexGeocell = HexGeocell.defaultGeocell() + ) + } + + var currentBounds by remember { mutableStateOf(null) } + var visibleMarkers by remember { mutableStateOf>>(emptyList()) } + + // Load markers dynamically based on viewport + LaunchedEffect(currentBounds) { + currentBounds?.let { bounds -> + // Native spatial query is extremely fast + visibleMarkers = nativeManager.findMarkersInBounds(bounds) + } + } + + Column { + Text("${visibleCountLabel}: ${'$'}{visibleMarkers.size}") + + // ${commentForMapViewUsage} + MapView( + state = mapViewState, + onCameraMove = { cameraPosition -> + currentBounds = cameraPosition.visibleRegion?.bounds + } + ) { + // Only visible markers are processed + } + } +}`; +--- + + + diff --git a/docs/src/components/experimental/marker-native-strategy/NativeBatchOperationsExample.astro b/docs/src/components/experimental/marker-native-strategy/NativeBatchOperationsExample.astro new file mode 100644 index 00000000..2612d3c5 --- /dev/null +++ b/docs/src/components/experimental/marker-native-strategy/NativeBatchOperationsExample.astro @@ -0,0 +1,28 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `suspend fun batchNativeOperations(nativeManager: NativeMarkerManager) { + val markersBatch = generateMarkerBatch(10000) // 10,000 markers + + // Efficient batch registration + withContext(Dispatchers.Default) { + markersBatch.forEach { markerData -> + val entity = MarkerEntityInterface( + state = MarkerState( + id = markerData.id, + position = markerData.position, + icon = DefaultIcon() + ) + ) + nativeManager.registerEntity(entity) + } + } + + // Verify registration + val totalMarkers = nativeManager.allEntities().size + println("Registered ${'$'}totalMarkers markers in native index") +}`; +--- + + + diff --git a/docs/src/components/experimental/marker-native-strategy/NativeBenchmarkExample.astro b/docs/src/components/experimental/marker-native-strategy/NativeBenchmarkExample.astro new file mode 100644 index 00000000..d28f8230 --- /dev/null +++ b/docs/src/components/experimental/marker-native-strategy/NativeBenchmarkExample.astro @@ -0,0 +1,39 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `suspend fun benchmarkNativePerformance() { + val standardManager = MarkerManager(HexGeocell.defaultGeocell()) + val nativeManager = NativeMarkerManager(HexGeocell.defaultGeocell()) + + val testMarkers = generateTestDataset(50000) // 50,000 markers + + // Benchmark registration + val standardTime = measureTimeMillis { + testMarkers.forEach { standardManager.registerEntity(it) } + } + + val nativeTime = measureTimeMillis { + testMarkers.forEach { nativeManager.registerEntity(it) } + } + + // Benchmark spatial queries + val testBounds = GeoRectBounds( + southWest = GeoPoint.fromLatLong(37.7700, -122.4250), + northEast = GeoPoint.fromLatLong(37.7800, -122.4150) + ) + + val standardQueryTime = measureTimeMillis { + repeat(1000) { standardManager.findMarkersInBounds(testBounds) } + } + + val nativeQueryTime = measureTimeMillis { + repeat(1000) { nativeManager.findMarkersInBounds(testBounds) } + } + + println("Registration - Standard: ${'$'}{standardTime}ms, Native: ${'$'}{nativeTime}ms") + println("Queries - Standard: ${'$'}{standardQueryTime}ms, Native: ${'$'}{nativeQueryTime}ms") +}`; +--- + + + diff --git a/docs/src/components/experimental/marker-native-strategy/NativeClusteringExampleComposable.astro b/docs/src/components/experimental/marker-native-strategy/NativeClusteringExampleComposable.astro new file mode 100644 index 00000000..63c71448 --- /dev/null +++ b/docs/src/components/experimental/marker-native-strategy/NativeClusteringExampleComposable.astro @@ -0,0 +1,57 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `@Composable +fun NativeClusteringExample() { + val clusteringStrategy = remember { + NativeSpatialMarkerStrategy( + clusteringEnabled = true, + clusterThreshold = 50, // Cluster when > 50 markers nearby + clusterRadius = 100.0, // 100-meter clustering radius + geocell = HexGeocell.defaultGeocell() + ) + } + + val nativeManager = remember { + NativeMarkerManager( + hexGeocell = HexGeocell.defaultGeocell() + ) + } + + // Add large dataset for clustering + LaunchedEffect(Unit) { + val denseMarkers = generateDenseMarkerCluster( + center = GeoPoint.fromLatLong(37.7749, -122.4194), + count = 1000, + radiusMeters = 500.0 // 500 meters + ) + + denseMarkers.forEach { markerData -> + val entity = MarkerEntityInterface( + state = MarkerState( + id = markerData.id, + position = markerData.position, + icon = DefaultIcon(fillColor = Color.Blue, scale = 0.8f) + ) + ) + nativeManager.registerEntity(entity) + } + } + + // ${commentForMapViewUsage} + MapView(state = mapViewState) { + // Native clustering automatically groups nearby markers + } +}`; +--- + + + diff --git a/docs/src/components/experimental/marker-native-strategy/NativeDirectQueriesExample.astro b/docs/src/components/experimental/marker-native-strategy/NativeDirectQueriesExample.astro new file mode 100644 index 00000000..930f2058 --- /dev/null +++ b/docs/src/components/experimental/marker-native-strategy/NativeDirectQueriesExample.astro @@ -0,0 +1,24 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `fun performNativeQueries(nativeManager: NativeMarkerManager) { + val center = GeoPoint.fromLatLong(37.7749, -122.4194) + val bounds = GeoRectBounds( + southWest = GeoPoint.fromLatLong(37.7700, -122.4250), + northEast = GeoPoint.fromLatLong(37.7800, -122.4150) + ) + + // Native spatial queries are extremely fast + val nearestMarker = nativeManager.findNearest(center) + val boundedMarkers = nativeManager.findMarkersInBounds(bounds) + val totalMarkers = nativeManager.allEntities().size + + // Memory and performance stats + val stats = nativeManager.getNativeMemoryStats() + println("Query performance: ${'$'}{stats.nativeIndexCount} indexed markers") + println("Memory usage: ${'$'}{stats.estimatedMemoryKB} KB") +}`; +--- + + + diff --git a/docs/src/components/experimental/marker-native-strategy/NativeLibraryFallbackExample.astro b/docs/src/components/experimental/marker-native-strategy/NativeLibraryFallbackExample.astro new file mode 100644 index 00000000..f1a8dcfb --- /dev/null +++ b/docs/src/components/experimental/marker-native-strategy/NativeLibraryFallbackExample.astro @@ -0,0 +1,19 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `// Check native library availability +try { + val nativeManager = NativeMarkerManager( + hexGeocell = HexGeocell.defaultGeocell() + ) + // Native library loaded successfully +} catch (e: UnsatisfiedLinkError) { + // Fallback to standard marker manager + val standardManager = MarkerManager( + hexGeocell = HexGeocell.defaultGeocell() + ) +}`; +--- + + + diff --git a/docs/src/components/experimental/marker-native-strategy/NativeMarkerGradleDependencies.astro b/docs/src/components/experimental/marker-native-strategy/NativeMarkerGradleDependencies.astro new file mode 100644 index 00000000..9867d698 --- /dev/null +++ b/docs/src/components/experimental/marker-native-strategy/NativeMarkerGradleDependencies.astro @@ -0,0 +1,32 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForBom?: string; + commentForCore?: string; + commentForChooseProvider?: string; + bomVersionPlaceholder?: string; +} + +const { + commentForBom = "Required: Bom module", + commentForCore = "Required: Core module", + commentForChooseProvider = "Choose your map provider", + bomVersionPlaceholder = "$version" +} = Astro.props; + +const code = `dependencies { + implementation "com.mapconductor:marker-native-strategy" + + // ${commentForBom} + implementation "com.mapconductor:mapconductor-bom:${bomVersionPlaceholder}" + // ${commentForCore} + implementation "com.mapconductor:core" + + // ${commentForChooseProvider} + implementation "com.mapconductor:for-googlemaps" +}`; +--- + + + diff --git a/docs/src/components/experimental/marker-native-strategy/NativeMarkerManagerUsage.astro b/docs/src/components/experimental/marker-native-strategy/NativeMarkerManagerUsage.astro new file mode 100644 index 00000000..54a49bf2 --- /dev/null +++ b/docs/src/components/experimental/marker-native-strategy/NativeMarkerManagerUsage.astro @@ -0,0 +1,19 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `import com.mapconductor.marker.nativestrategy.NativeMarkerManager +import com.mapconductor.core.geocell.HexGeocell + +// Create native marker manager +val nativeManager = NativeMarkerManager( + hexGeocell = HexGeocell.defaultGeocell() +) + +// Use like standard MarkerManager +nativeManager.registerEntity(markerEntity) +val nearestMarker = nativeManager.findNearest(position) +val markersInBounds = nativeManager.findMarkersInBounds(bounds)`; +--- + + + diff --git a/docs/src/components/experimental/marker-native-strategy/NativeMarkerNdkConfig.astro b/docs/src/components/experimental/marker-native-strategy/NativeMarkerNdkConfig.astro new file mode 100644 index 00000000..ce0c4380 --- /dev/null +++ b/docs/src/components/experimental/marker-native-strategy/NativeMarkerNdkConfig.astro @@ -0,0 +1,14 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `android { + defaultConfig { + ndk { + abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64' + } + } +}`; +--- + + + diff --git a/docs/src/components/experimental/marker-native-strategy/NativeMemoryLeakPreventionExample.astro b/docs/src/components/experimental/marker-native-strategy/NativeMemoryLeakPreventionExample.astro new file mode 100644 index 00000000..11ae4c1d --- /dev/null +++ b/docs/src/components/experimental/marker-native-strategy/NativeMemoryLeakPreventionExample.astro @@ -0,0 +1,24 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `class MarkerActivity : ComponentActivity() { + private var nativeManager: NativeMarkerManager? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + nativeManager = NativeMarkerManager(HexGeocell.defaultGeocell()) + } + + override fun onDestroy() { + super.onDestroy() + + // Critical: cleanup native resources + nativeManager?.destroy() + nativeManager = null + } +}`; +--- + + + diff --git a/docs/src/components/experimental/marker-native-strategy/NativeOptimizationConfigExample.astro b/docs/src/components/experimental/marker-native-strategy/NativeOptimizationConfigExample.astro new file mode 100644 index 00000000..205a6cb7 --- /dev/null +++ b/docs/src/components/experimental/marker-native-strategy/NativeOptimizationConfigExample.astro @@ -0,0 +1,23 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `// Optimal configuration for large datasets +val optimizedGeocell = HexGeocell( + baseHexSideLength = 500.0, // Smaller cells for dense data + zoom = 18.0 // Higher resolution +) + +val optimizedManager = NativeMarkerManager( + hexGeocell = optimizedGeocell +) + +// Optimal parallel strategy +val optimizedStrategy = SimpleNativeParallelStrategy( + expandMargin = 0.1, // Smaller expansion for performance + maxConcurrency = Runtime.getRuntime().availableProcessors(), + geocell = optimizedGeocell +)`; +--- + + + diff --git a/docs/src/components/experimental/marker-native-strategy/NativePerformanceExampleComposable.astro b/docs/src/components/experimental/marker-native-strategy/NativePerformanceExampleComposable.astro new file mode 100644 index 00000000..b13ff069 --- /dev/null +++ b/docs/src/components/experimental/marker-native-strategy/NativePerformanceExampleComposable.astro @@ -0,0 +1,47 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `@Composable +fun NativePerformanceExample() { + val nativeManager = remember { + NativeMarkerManager( + hexGeocell = HexGeocell.defaultGeocell() + ) + } + + var stats by remember { mutableStateOf(null) } + + // Monitor performance + LaunchedEffect(Unit) { + while (true) { + delay(5000) // Update every 5 seconds + stats = nativeManager.getNativeMemoryStats() + } + } + + Column { + stats?.let { s -> + Text("Markers: ${'$'}{s.entityCount}") + Text("Native Index: ${'$'}{s.nativeIndexCount}") + Text("Memory: ${'$'}{s.estimatedMemoryKB} KB") + Text("Pure Native: ${'$'}{s.usesPureNativeIndex}") + } + + // ${commentForMapViewUsage} + MapView(state = mapViewState) { + // Native-managed markers + } + } +}`; +--- + + + diff --git a/docs/src/components/experimental/marker-native-strategy/NativeResourceManagementExampleComposable.astro b/docs/src/components/experimental/marker-native-strategy/NativeResourceManagementExampleComposable.astro new file mode 100644 index 00000000..369e406d --- /dev/null +++ b/docs/src/components/experimental/marker-native-strategy/NativeResourceManagementExampleComposable.astro @@ -0,0 +1,53 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `@Composable +fun ResourceManagementExample() { + val nativeManager = remember { + NativeMarkerManager( + hexGeocell = HexGeocell.defaultGeocell() + ) + } + + // Proper cleanup is crucial for native resources + DisposableEffect(nativeManager) { + onDispose { + // Cleanup native resources + nativeManager.destroy() + } + } + + // Monitor memory usage + var memoryStats by remember { mutableStateOf(null) } + + LaunchedEffect(Unit) { + while (true) { + delay(10000) // Check every 10 seconds + memoryStats = nativeManager.getNativeMemoryStats() + + // Log memory usage for monitoring + memoryStats?.let { stats -> + if (stats.estimatedMemoryKB > 10000) { // > 10MB + println("High memory usage detected: ${'$'}{stats.estimatedMemoryKB} KB") + } + } + } + } + + // ${commentForMapViewUsage} + MapView(state = mapViewState) { + // Native-managed markers + } +}`; +--- + + + diff --git a/docs/src/components/experimental/marker-native-strategy/ParallelRenderingExampleComposable.astro b/docs/src/components/experimental/marker-native-strategy/ParallelRenderingExampleComposable.astro new file mode 100644 index 00000000..b00552cb --- /dev/null +++ b/docs/src/components/experimental/marker-native-strategy/ParallelRenderingExampleComposable.astro @@ -0,0 +1,41 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `@Composable +fun ParallelRenderingExample() { + val parallelStrategy = remember { + SimpleNativeParallelStrategy( + expandMargin = 0.3, // Larger viewport expansion + maxConcurrency = 6, // More parallel threads + geocell = HexGeocell( + baseHexSideLength = 1000.0, // Optimized cell size + zoom = 15.0 + ) + ) + } + + // Configure marker controller with parallel strategy + LaunchedEffect(mapViewState) { + mapViewState.getMapViewHolder()?.let { holder -> + // Setup parallel strategy with map controller + // Implementation depends on map provider + } + } + + // ${commentForMapViewUsage} + MapView(state = mapViewState) { + // Parallel-rendered markers + } +}`; +--- + + + diff --git a/docs/src/components/experimental/marker-native-strategy/SimpleNativeParallelStrategyConfig.astro b/docs/src/components/experimental/marker-native-strategy/SimpleNativeParallelStrategyConfig.astro new file mode 100644 index 00000000..eca7a2f8 --- /dev/null +++ b/docs/src/components/experimental/marker-native-strategy/SimpleNativeParallelStrategyConfig.astro @@ -0,0 +1,24 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + expandMargin?: number; + maxConcurrency?: number; +} + +const { + expandMargin = 0.2, + maxConcurrency = 4 +} = Astro.props; + +const code = `import com.mapconductor.marker.nativestrategy.SimpleNativeParallelStrategy + +val strategy = SimpleNativeParallelStrategy( + expandMargin = ${expandMargin}, // Viewport expansion + maxConcurrency = ${maxConcurrency}, // Parallel threads + geocell = HexGeocell.defaultGeocell() +)`; +--- + + + diff --git a/docs/src/components/experimental/marker-strategy/ClusteringStrategyExampleComposable.astro b/docs/src/components/experimental/marker-strategy/ClusteringStrategyExampleComposable.astro new file mode 100644 index 00000000..e3638821 --- /dev/null +++ b/docs/src/components/experimental/marker-strategy/ClusteringStrategyExampleComposable.astro @@ -0,0 +1,58 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `@Composable +fun ClusteringStrategyExample() { + val clusterStrategy = remember { + SpatialMarkerStrategy( + clusteringEnabled = true, + clusterRadius = 50.0, // 50-meter clustering + maxMarkersPerCluster = 5, // Small clusters + geocell = HexGeocell( + baseHexSideLength = 100.0, // Fine-grained spatial index + zoom = 18.0 + ) + ) + } + + // Add dense marker dataset + LaunchedEffect(Unit) { + val denseMarkers = generateDenseMarkerSet( + center = GeoPoint.fromLatLong(37.7749, -122.4194), + count = 500, + radiusMeters = 200.0 // 200-meter radius + ) + + denseMarkers.forEach { markerData -> + val entity = MarkerEntityInterface( + state = MarkerState( + id = markerData.id, + position = markerData.position, + icon = DefaultIcon( + fillColor = markerData.category.color, + scale = 0.8f + ) + ) + ) + + clusterStrategy.markerManager.registerEntity(entity) + } + } + + // ${commentForMapViewUsage} + GoogleMapView(state = mapViewState) { + // Clustering strategy automatically groups nearby markers + } +}`; +--- + + + diff --git a/docs/src/components/experimental/marker-strategy/CustomMarkerStrategyExample.astro b/docs/src/components/experimental/marker-strategy/CustomMarkerStrategyExample.astro new file mode 100644 index 00000000..bee9ed71 --- /dev/null +++ b/docs/src/components/experimental/marker-strategy/CustomMarkerStrategyExample.astro @@ -0,0 +1,71 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForCustomRenderingLogic?: string; + commentForManagementLogic?: string; + commentForUseRenderer?: string; + commentForVisibleLogic?: string; + commentForHiddenLogic?: string; +} + +const { + commentForCustomRenderingLogic = 'Custom rendering logic', + commentForManagementLogic = 'Your custom marker management here', + commentForUseRenderer = 'Use renderer to update display', + commentForVisibleLogic = 'Your custom logic to determine which markers should be visible', + commentForHiddenLogic = 'Your custom logic to determine which markers should be hidden', +} = Astro.props; + +const code = `class CustomMarkerStrategy( + semaphore: Semaphore = Semaphore(1), + geocell: HexGeocellInterface = HexGeocell.defaultGeocell() +) : AbstractViewportStrategy(semaphore, geocell) { + + override suspend fun onCameraChanged( + cameraPosition: MapCameraPosition, + renderer: MarkerOverlayRendererInterface + ) { + semaphore.withPermit { + // ${commentForCustomRenderingLogic} + val visibleBounds = cameraPosition.visibleRegion?.bounds ?: return + + // ${commentForManagementLogic} + val markersToShow = determineVisibleMarkers(visibleBounds) + val markersToHide = determineHiddenMarkers(visibleBounds) + + // ${commentForUseRenderer} + if (markersToHide.isNotEmpty()) { + renderer.onRemove(markersToHide) + } + + if (markersToShow.isNotEmpty()) { + val addParams = markersToShow.map { entity -> + object : MarkerOverlayRendererInterface.AddParamsInterface { + override val state: MarkerState = entity.state + override val bitmapIcon: BitmapIcon = entity.state.icon?.toBitmapIcon() ?: defaultIcon + } + } + renderer.onAdd(addParams) + } + + renderer.onPostProcess() + } + } + + private fun determineVisibleMarkers(bounds: GeoRectBounds): List> { + // ${commentForVisibleLogic} + return markerManager.findMarkersInBounds(bounds) + } + + private fun determineHiddenMarkers(bounds: GeoRectBounds): List> { + // ${commentForHiddenLogic} + return markerManager.allEntities().filter { entity -> + entity.isRendered && !bounds.contains(entity.state.position) + } + } +}`; +--- + + + diff --git a/docs/src/components/experimental/marker-strategy/DefaultMarkerStrategyConfig.astro b/docs/src/components/experimental/marker-strategy/DefaultMarkerStrategyConfig.astro new file mode 100644 index 00000000..3815f4a2 --- /dev/null +++ b/docs/src/components/experimental/marker-strategy/DefaultMarkerStrategyConfig.astro @@ -0,0 +1,22 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + expandMargin?: number; +} + +const { + expandMargin = 0.2 +} = Astro.props; + +const code = `import com.mapconductor.marker.strategy.DefaultMarkerStrategy + +val defaultStrategy = DefaultMarkerStrategy( + expandMargin = ${expandMargin}, // 20% viewport expansion + semaphore = Semaphore(1), + geocell = HexGeocell.defaultGeocell() +)`; +--- + + + diff --git a/docs/src/components/experimental/marker-strategy/DefaultStrategyExampleComposable.astro b/docs/src/components/experimental/marker-strategy/DefaultStrategyExampleComposable.astro new file mode 100644 index 00000000..426f2b50 --- /dev/null +++ b/docs/src/components/experimental/marker-strategy/DefaultStrategyExampleComposable.astro @@ -0,0 +1,37 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `@Composable +fun DefaultStrategyExample() { + val mapViewState = rememberGoogleMapViewState() + + val markerStrategy = remember { + DefaultMarkerStrategy( + expandMargin = 0.2 + ) + } + + // Configure strategy with map controller + LaunchedEffect(mapViewState) { + // Strategy setup depends on map provider implementation + // This is typically handled by the map provider's marker controller + } + + // ${commentForMapViewUsage} + GoogleMapView(state = mapViewState) { + // Markers are managed by the strategy + // Add markers programmatically through the strategy + } +}`; +--- + + + diff --git a/docs/src/components/experimental/marker-strategy/DynamicLoadingExampleComposable.astro b/docs/src/components/experimental/marker-strategy/DynamicLoadingExampleComposable.astro new file mode 100644 index 00000000..ad249fcf --- /dev/null +++ b/docs/src/components/experimental/marker-strategy/DynamicLoadingExampleComposable.astro @@ -0,0 +1,59 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `@Composable +fun DynamicLoadingExample() { + val mapViewState = rememberGoogleMapViewState() + var currentBounds by remember { mutableStateOf(null) } + var loadedMarkers by remember { mutableStateOf>(emptySet()) } + + val strategy = remember { + DefaultMarkerStrategy( + expandMargin = 0.3 // Larger margin for preloading + ) + } + + // Load markers dynamically based on viewport + LaunchedEffect(currentBounds) { + currentBounds?.let { bounds -> + val newMarkers = fetchMarkersForBounds(bounds) // Your API call + + newMarkers.forEach { markerData -> + if (markerData.id !in loadedMarkers) { + val entity = MarkerEntityInterface( + state = MarkerState( + id = markerData.id, + position = markerData.position, + icon = DefaultIcon() + ) + ) + + strategy.markerManager.registerEntity(entity) + loadedMarkers = loadedMarkers + markerData.id + } + } + } + } + + // ${commentForMapViewUsage} + GoogleMapView( + state = mapViewState, + onCameraMove = { cameraPosition -> + currentBounds = cameraPosition.visibleRegion?.bounds + } + ) { + // Strategy manages dynamic marker loading + } +}`; +--- + + + diff --git a/docs/src/components/experimental/marker-strategy/MarkerStrategyGradleDependencies.astro b/docs/src/components/experimental/marker-strategy/MarkerStrategyGradleDependencies.astro new file mode 100644 index 00000000..732762e4 --- /dev/null +++ b/docs/src/components/experimental/marker-strategy/MarkerStrategyGradleDependencies.astro @@ -0,0 +1,32 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForBom?: string; + commentForCore?: string; + commentForChooseProvider?: string; + bomVersionPlaceholder?: string; +} + +const { + commentForBom = "Required: Core module", + commentForCore = "Required: Core module", + commentForChooseProvider = "Choose your map provider", + bomVersionPlaceholder = "$version" +} = Astro.props; + +const code = `dependencies { + implementation "com.mapconductor:marker-strategy" + + // ${commentForBom} + implementation "com.mapconductor:mapconductor-bom:${bomVersionPlaceholder}" + // ${commentForCore} + implementation "com.mapconductor:core" + + // ${commentForChooseProvider} + implementation "com.mapconductor:for-googlemaps" +}`; +--- + + + diff --git a/docs/src/components/experimental/marker-strategy/MigrationBasicToStrategyComposable.astro b/docs/src/components/experimental/marker-strategy/MigrationBasicToStrategyComposable.astro new file mode 100644 index 00000000..28c629f3 --- /dev/null +++ b/docs/src/components/experimental/marker-strategy/MigrationBasicToStrategyComposable.astro @@ -0,0 +1,51 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `// Before: Basic marker management +@Composable +fun BasicMarkers() { + MapView(state = mapViewState) { + markers.forEach { markerData -> + Marker( + position = markerData.position, + icon = DefaultIcon() + ) + } + } +} + +// After: Strategy-based management +@Composable +fun StrategyMarkers() { + val strategy = remember { DefaultMarkerStrategy() } + + LaunchedEffect(markers) { + markers.forEach { markerData -> + val entity = MarkerEntityInterface( + state = MarkerState( + id = markerData.id, + position = markerData.position, + icon = DefaultIcon() + ) + ) + strategy.markerManager.registerEntity(entity) + } + } + + // ${commentForMapViewUsage} + MapView(state = mapViewState) { + // Strategy handles all marker rendering + } +}`; +--- + + + diff --git a/docs/src/components/experimental/marker-strategy/PerformanceStrategyConfigExample.astro b/docs/src/components/experimental/marker-strategy/PerformanceStrategyConfigExample.astro new file mode 100644 index 00000000..8db205e9 --- /dev/null +++ b/docs/src/components/experimental/marker-strategy/PerformanceStrategyConfigExample.astro @@ -0,0 +1,25 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +const code = `// High-performance configuration +val performanceStrategy = DefaultMarkerStrategy( + expandMargin = 0.1, // Smaller margin for less preloading + semaphore = Semaphore(2), // Allow some parallelism + geocell = HexGeocell( + baseHexSideLength = 1000.0, // Larger cells for better performance + zoom = 15.0 // Lower resolution for speed + ) +) + +// Memory-optimized configuration +val memoryStrategy = SimpleMarkerStrategy( + expandMargin = 0.05, // Minimal expansion + geocell = HexGeocell( + baseHexSideLength = 2000.0, // Very large cells + zoom = 12.0 // Lower resolution + ) +)`; +--- + + + diff --git a/docs/src/components/experimental/marker-strategy/SimpleMarkerStrategyConfig.astro b/docs/src/components/experimental/marker-strategy/SimpleMarkerStrategyConfig.astro new file mode 100644 index 00000000..f792c476 --- /dev/null +++ b/docs/src/components/experimental/marker-strategy/SimpleMarkerStrategyConfig.astro @@ -0,0 +1,21 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + expandMargin?: number; +} + +const { + expandMargin = 0.15 +} = Astro.props; + +const code = `import com.mapconductor.marker.strategy.SimpleMarkerStrategy + +val simpleStrategy = SimpleMarkerStrategy( + expandMargin = ${expandMargin}, + geocell = HexGeocell.defaultGeocell() +)`; +--- + + + diff --git a/docs/src/components/experimental/marker-strategy/SpatialMarkerStrategyConfig.astro b/docs/src/components/experimental/marker-strategy/SpatialMarkerStrategyConfig.astro new file mode 100644 index 00000000..74ec9027 --- /dev/null +++ b/docs/src/components/experimental/marker-strategy/SpatialMarkerStrategyConfig.astro @@ -0,0 +1,25 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + clusterRadius?: number; + maxMarkersPerCluster?: number; +} + +const { + clusterRadius = 100.0, + maxMarkersPerCluster = 10 +} = Astro.props; + +const code = `import com.mapconductor.marker.strategy.SpatialMarkerStrategy + +val spatialStrategy = SpatialMarkerStrategy( + clusteringEnabled = true, + clusterRadius = ${clusterRadius}, // Clustering radius (meters) + maxMarkersPerCluster = ${maxMarkersPerCluster}, // Maximum markers in a cluster + geocell = HexGeocell.defaultGeocell() +)`; +--- + + + diff --git a/docs/src/components/experimental/marker-strategy/StrategyMarkerManagementComposable.astro b/docs/src/components/experimental/marker-strategy/StrategyMarkerManagementComposable.astro new file mode 100644 index 00000000..a33fadc4 --- /dev/null +++ b/docs/src/components/experimental/marker-strategy/StrategyMarkerManagementComposable.astro @@ -0,0 +1,44 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `@Composable +fun StrategyMarkerManagement() { + val markerStrategy = remember { + DefaultMarkerStrategy() + } + + LaunchedEffect(Unit) { + // Add markers to the strategy's manager + val markers = loadMarkerData() // Your marker data + + markers.forEach { markerData -> + val entity = MarkerEntityInterface( + state = MarkerState( + id = markerData.id, + position = markerData.position, + icon = DefaultIcon(fillColor = markerData.color) + ) + ) + + // Register with strategy's marker manager + markerStrategy.markerManager.registerEntity(entity) + } + } + + // ${commentForMapViewUsage} + GoogleMapView(state = mapViewState) { + // Strategy handles marker rendering automatically + } +}`; +--- + + + diff --git a/docs/src/components/experimental/marker-strategy/StrategyPerformanceMonitoringComposable.astro b/docs/src/components/experimental/marker-strategy/StrategyPerformanceMonitoringComposable.astro new file mode 100644 index 00000000..193f62c5 --- /dev/null +++ b/docs/src/components/experimental/marker-strategy/StrategyPerformanceMonitoringComposable.astro @@ -0,0 +1,42 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentForMapViewUsage?: string; +} + +const { + commentForMapViewUsage = "Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView" +} = Astro.props; + +const code = `@Composable +fun StrategyPerformanceMonitoring() { + val strategy = remember { DefaultMarkerStrategy() } + var performanceStats by remember { mutableStateOf("") } + + LaunchedEffect(Unit) { + while (true) { + delay(5000) + + val stats = strategy.markerManager.getMemoryStats() + performanceStats = buildString { + appendLine("Entities: ${'$'}{stats.entityCount}") + appendLine("Memory: ${'$'}{stats.estimatedMemoryKB} KB") + appendLine("Spatial Index: ${'$'}{stats.hasSpatialIndex}") + } + } + } + + Column { + Text(performanceStats) + + // ${commentForMapViewUsage} + GoogleMapView(state = mapViewState) { + // Strategy-managed markers + } + } +}`; +--- + + + diff --git a/docs/src/components/get-started/CameraMoveEvents.astro b/docs/src/components/get-started/CameraMoveEvents.astro new file mode 100644 index 00000000..c68fa055 --- /dev/null +++ b/docs/src/components/get-started/CameraMoveEvents.astro @@ -0,0 +1,35 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentMarkers?: string; + cameraMoveStartMessage?: string; + cameraMoveMessage?: string; + cameraMoveEndMessage?: string; +} + +const { + commentMarkers = "マーカーなど", + cameraMoveStartMessage = "カメラの移動が開始されました", + cameraMoveMessage = "カメラ位置: ", + cameraMoveEndMessage = "カメラの移動が終了しました" +} = Astro.props; + +const code = `GoogleMapView( + modifier = modifier.fillMaxSize(), + state = mapViewState, + onCameraMoveStart = { + println("${cameraMoveStartMessage}") + }, + onCameraMove = { cameraPosition -> + println("${cameraMoveMessage}\${cameraPosition.position.latitude}, \${cameraPosition.position.longitude}") + }, + onCameraMoveEnd = { + println("${cameraMoveEndMessage}") + } +) { + // ${commentMarkers} +}`; +--- + + diff --git a/docs/src/components/get-started/CircleExample.astro b/docs/src/components/get-started/CircleExample.astro new file mode 100644 index 00000000..ce986844 --- /dev/null +++ b/docs/src/components/get-started/CircleExample.astro @@ -0,0 +1,52 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + markerLabel?: string; + markerLat?: number; + markerLong?: number; + radiusMeters?: number; + strokeWidth?: string; + commentMarker?: string; + commentDrawCircle?: string; + commentRadiusUnit?: string; + commentStrokeUnit?: string; +} + +const { + markerLabel = "TT", + markerLat = 35.6586, + markerLong = 139.7454, + radiusMeters = 1000.0, + strokeWidth = "3.dp", + commentMarker = "マーカー", + commentDrawCircle = "東京タワーの周りに半径1kmの円を描画", + commentRadiusUnit = "メートル単位", + commentStrokeUnit = "Dp単位" +} = Astro.props; + +const code = `import androidx.compose.ui.graphics.Color + +GoogleMapView( + modifier = modifier.fillMaxSize(), + state = mapViewState +) { + // ${commentMarker} + Marker( + position = GeoPoint.fromLatLong(${markerLat}, ${markerLong}), + icon = DefaultIcon(label = "${markerLabel}"), + extra = "tokyo_tower" + ) + + // ${commentDrawCircle} + Circle( + center = GeoPoint.fromLatLong(${markerLat}, ${markerLong}), + radiusMeters = ${radiusMeters}, // ${commentRadiusUnit} + strokeColor = Color.Blue, + strokeWidth = ${strokeWidth}, // ${commentStrokeUnit} + fillColor = Color.Blue.copy(alpha = 0.2f) + ) +}`; +--- + + diff --git a/docs/src/components/get-started/CompleteSample.astro b/docs/src/components/get-started/CompleteSample.astro new file mode 100644 index 00000000..91132e43 --- /dev/null +++ b/docs/src/components/get-started/CompleteSample.astro @@ -0,0 +1,185 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + marker1Label?: string; + marker1Lat?: number; + marker1Long?: number; + marker2Label?: string; + marker2Lat?: number; + marker2Long?: number; + centerLat?: number; + centerLong?: number; + circleRadiusMeters?: number; + commentPositions?: string; + commentClickedPosition?: string; + commentControlButtons?: string; + commentMap?: string; + commentMarkers?: string; + commentClickedMarker?: string; + commentCircle?: string; + commentPolyline?: string; +} + +const { + marker1Label = "TT", + marker1Lat = 35.6586, + marker1Long = 139.7454, + marker2Label = "ST", + marker2Lat = 35.7101, + marker2Long = 139.8107, + centerLat = 35.6812, + centerLong = 139.7671, + circleRadiusMeters = 1000.0, + commentPositions = "位置情報", + commentClickedPosition = "クリックされた位置を保存", + commentControlButtons = "コントロールボタン", + commentMap = "地図", + commentMarkers = "マーカー", + commentClickedMarker = "クリックされた位置のマーカー", + commentCircle = "円", + commentPolyline = "ポリライン" +} = Astro.props; + +const code = `import androidx.compose.foundation.layout.* +import androidx.compose.material3.Button +import androidx.compose.material3.Text +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import com.mapconductor.core.* +import com.mapconductor.googlemaps.GoogleMapView +import com.mapconductor.googlemaps.rememberGoogleMapViewState +import kotlinx.coroutines.launch + +@Composable +fun CompleteSample(modifier: Modifier = Modifier) { + val context = LocalContext.current + + // ${commentPositions} + val marker1 = GeoPoint.fromLatLong(${marker1Lat}, ${marker1Long}) + val marker2 = GeoPoint.fromLatLong(${marker2Lat}, ${marker2Long}) + + // ${commentClickedPosition} + var clickedPosition by remember { mutableStateOf(null) } + + val initialCamera = MapCameraPosition( + position = GeoPoint.fromLatLong(${centerLat}, ${centerLong}), + zoom = 12.0 + ) + + val mapViewState = rememberGoogleMapViewState( + cameraPosition = initialCamera + ) + val scope = rememberCoroutineScope() + val onMarkerClick: (MarkerState) -> Unit = { markerState -> + Toast + .makeText( + context, + "clicked: \${markerState.extra}", + Toast.LENGTH_SHORT, + ) + .show() + } + + Column(modifier = modifier.fillMaxSize()) { + // ${commentControlButtons} + Row( + modifier = Modifier + .fillMaxWidth() + .padding(8.dp), + horizontalArrangement = Arrangement.SpaceEvenly + ) { + Button(onClick = { + scope.launch { + mapViewState.moveCameraTo( + MapCameraPosition(position = marker1, zoom = 15.0), + durationMillis = 1000 + ) + } + }) { + Text("${marker1Label}") + } + + Button(onClick = { + scope.launch { + mapViewState.moveCameraTo( + MapCameraPosition(position = marker2, zoom = 15.0), + durationMillis = 1000 + ) + } + }) { + Text("${marker2Label}") + } + } + + // ${commentMap} + GoogleMapView( + modifier = Modifier.fillMaxSize(), + state = mapViewState, + onMapClick = { geoPoint -> + clickedPosition = geoPoint + } + ) { + // ${commentMarkers} + Marker( + position = marker1, + icon = DefaultIcon( + label = "${marker1Label}", + fillColor = Color.Red, + ), + extra = "marker1", + onClick = onMarkerClick + ) + + Marker( + position = marker2, + icon = DefaultIcon( + label = "${marker2Label}", + fillColor = Color.Blue + ), + extra = "marker2", + onClick = onMarkerClick + ) + + // ${commentClickedMarker} + clickedPosition?.let { position -> + Marker( + position = position, + icon = DefaultIcon( + label = "!", + fillColor = Color.Green + ), + extra = "clicked", + onClick = onMarkerClick + ) + } + + // ${commentCircle} + Circle( + center = marker1, + radiusMeters = ${circleRadiusMeters}, + strokeColor = Color.Red, + fillColor = Color.Red.copy(alpha = 0.2f) + ) + + Circle( + center = marker2, + radiusMeters = ${circleRadiusMeters}, + strokeColor = Color.Blue, + fillColor = Color.Blue.copy(alpha = 0.2f) + ) + + // ${commentPolyline} + Polyline( + points = listOf(marker1, marker2), + strokeColor = Color.Magenta, + strokeWidth = 3.dp + ) + } + } +}`; +--- + + diff --git a/docs/src/components/get-started/DependencyConfigTabs.astro b/docs/src/components/get-started/DependencyConfigTabs.astro new file mode 100644 index 00000000..7fdf3b3e --- /dev/null +++ b/docs/src/components/get-started/DependencyConfigTabs.astro @@ -0,0 +1,95 @@ +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; +import { Code } from '@astrojs/starlight/components'; + +interface Props { + bomVersion?: string; + googleMapsIncluded?: boolean; + mapboxIncluded?: boolean; + hereIncluded?: boolean; + arcgisIncluded?: boolean; + maplibreIncluded?: boolean; + commentBOM?: string; + commentCore?: string; + commentGoogleMaps?: string; + commentOrMapbox?: string; + commentOrHere?: string; + commentOrArcGIS?: string; + commentOrMapLibre?: string; +} + +const { + bomVersion = "{BOM_MODULE_VERSION}", + googleMapsIncluded = true, + mapboxIncluded = false, + hereIncluded = false, + arcgisIncluded = false, + maplibreIncluded = false, + commentBOM = "BOM を利用してバージョンを統一", + commentCore = "コアモジュール(必須)", + commentGoogleMaps = "Google Maps を使う場合", + commentOrMapbox = "または Mapbox を使う場合", + commentOrHere = "または HERE Maps を使う場合", + commentOrArcGIS = "または ArcGIS を使う場合", + commentOrMapLibre = "または MapLibre を使う場合" +} = Astro.props; + +const kotlinCode = `dependencies { + val mapconductorVersion = "${bomVersion}" + + // ${commentBOM} + implementation(platform("com.mapconductor:mapconductor-bom:$mapconductorVersion")) + + // ${commentCore} + implementation("com.mapconductor:core") + + // ${commentGoogleMaps} + ${googleMapsIncluded ? 'implementation("com.mapconductor:for-googlemaps")' : '// implementation("com.mapconductor:for-googlemaps")'} + + // ${commentOrMapbox} + ${mapboxIncluded ? 'implementation("com.mapconductor:for-mapbox")' : '// implementation("com.mapconductor:for-mapbox")'} + + // ${commentOrHere} + ${hereIncluded ? 'implementation("com.mapconductor:for-here")' : '// implementation("com.mapconductor:for-here")'} + + // ${commentOrArcGIS} + ${arcgisIncluded ? 'implementation("com.mapconductor:for-arcgis")' : '// implementation("com.mapconductor:for-arcgis")'} + + // ${commentOrMapLibre} + ${maplibreIncluded ? 'implementation("com.mapconductor:for-maplibre")' : '// implementation("com.mapconductor:for-maplibre")'} +}`; + +const groovyCode = `dependencies { + def mapconductorVersion = "${bomVersion}" + + // ${commentBOM} + implementation platform("com.mapconductor:mapconductor-bom:$mapconductorVersion") + + // ${commentCore} + implementation "com.mapconductor:core" + + // ${commentGoogleMaps} + ${googleMapsIncluded ? 'implementation "com.mapconductor:for-googlemaps"' : '// implementation "com.mapconductor:for-googlemaps"'} + + // ${commentOrMapbox} + ${mapboxIncluded ? 'implementation "com.mapconductor:for-mapbox"' : '// implementation "com.mapconductor:for-mapbox"'} + + // ${commentOrHere} + ${hereIncluded ? 'implementation "com.mapconductor:for-here"' : '// implementation "com.mapconductor:for-here"'} + + // ${commentOrArcGIS} + ${arcgisIncluded ? 'implementation "com.mapconductor:for-arcgis"' : '// implementation "com.mapconductor:for-arcgis"'} + + // ${commentOrMapLibre} + ${maplibreIncluded ? 'implementation "com.mapconductor:for-maplibre"' : '// implementation "com.mapconductor:for-maplibre"'} +}`; +--- + + + + + + + + + diff --git a/docs/src/components/get-started/InteractiveMap.astro b/docs/src/components/get-started/InteractiveMap.astro new file mode 100644 index 00000000..cf6abc50 --- /dev/null +++ b/docs/src/components/get-started/InteractiveMap.astro @@ -0,0 +1,60 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + lat?: number; + long?: number; + zoom?: number; + clickLabelIcon?: string; + commentMapClicked?: string; + commentClickPosition?: string; + commentShowMarker?: string; +} + +const { + lat = 35.6812, + long = 139.7671, + zoom = 12.0, + clickLabelIcon = "!", + commentMapClicked = "地図がクリックされたときの処理", + commentClickPosition = "クリック位置: ", + commentShowMarker = "クリックした位置にマーカーを表示" +} = Astro.props; + +const code = `import androidx.compose.runtime.* + +@Composable +fun InteractiveMap(modifier: Modifier = Modifier) { + var clickedPosition by remember { mutableStateOf(null) } + + val initialCamera = MapCameraPosition( + position = GeoPoint.fromLatLong(${lat}, ${long}), + zoom = ${zoom} + ) + + val mapViewState = rememberGoogleMapViewState( + cameraPosition = initialCamera + ) + + GoogleMapView( + modifier = modifier.fillMaxSize(), + state = mapViewState, + onMapClick = { geoPoint -> + // ${commentMapClicked} + clickedPosition = geoPoint + println("${commentClickPosition}\${geoPoint.latitude}, \${geoPoint.longitude}") + } + ) { + // ${commentShowMarker} + clickedPosition?.let { position -> + Marker( + position = position, + icon = DefaultIcon(label = "${clickLabelIcon}"), + extra = "clicked_marker" + ) + } + } +}`; +--- + + diff --git a/docs/src/components/get-started/MapWithCameraControl.astro b/docs/src/components/get-started/MapWithCameraControl.astro new file mode 100644 index 00000000..1ff8ae8e --- /dev/null +++ b/docs/src/components/get-started/MapWithCameraControl.astro @@ -0,0 +1,101 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + button1Label?: string; + button1Lat?: number; + button1Long?: number; + button1Zoom?: number; + button2Label?: string; + button2Lat?: number; + button2Long?: number; + button2Zoom?: number; + marker1Label?: string; + marker2Label?: string; + commentButtons?: string; + commentMap?: string; +} + +const { + button1Label = "Tokyo Tower", + button1Lat = 35.6586, + button1Long = 139.7454, + button1Zoom = 15.0, + button2Label = "Sky Tree", + button2Lat = 35.7101, + button2Long = 139.8107, + button2Zoom = 15.0, + marker1Label = "TT", + marker2Label = "ST", + commentButtons = "ボタン", + commentMap = "地図" +} = Astro.props; + +const code = `import androidx.compose.foundation.layout.* +import androidx.compose.material3.Button +import androidx.compose.material3.Text +import androidx.compose.runtime.rememberCoroutineScope +import kotlinx.coroutines.launch + +@Composable +fun MapWithCameraControl(modifier: Modifier = Modifier) { + val marker1 = GeoPoint.fromLatLong(${button1Lat}, ${button1Long}) + val marker2 = GeoPoint.fromLatLong(${button2Lat}, ${button2Long}) + + val mapViewState = rememberGoogleMapViewState( + cameraPosition = MapCameraPosition( + position = marker1, + zoom = 12.0 + ) + ) + + val scope = rememberCoroutineScope() + + Column(modifier = modifier.fillMaxSize()) { + // ${commentButtons} + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceEvenly + ) { + Button(onClick = { + scope.launch { + mapViewState.moveCameraTo( + MapCameraPosition( + position = marker1, + zoom = ${button1Zoom} + ), + durationMillis = 1000 + ) + } + }) { + Text("${button1Label}") + } + + Button(onClick = { + scope.launch { + mapViewState.moveCameraTo( + MapCameraPosition( + position = marker2, + zoom = ${button2Zoom} + ), + durationMillis = 1000 + ) + } + }) { + Text("${button2Label}") + } + } + + // 地図 + GoogleMapView( + modifier = Modifier.fillMaxSize(), + state = mapViewState + ) { + Marker(position = marker1, icon = DefaultIcon(label = "${marker1Label}")) + Marker(position = marker2, icon = DefaultIcon(label = "${marker2Label}")) + } + } +}`; +--- + + diff --git a/docs/src/components/get-started/MapWithMarkers.astro b/docs/src/components/get-started/MapWithMarkers.astro new file mode 100644 index 00000000..6faca652 --- /dev/null +++ b/docs/src/components/get-started/MapWithMarkers.astro @@ -0,0 +1,84 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + marker1Label?: string; + marker1Lat?: number; + marker1Long?: number; + marker2Label?: string; + marker2Lat?: number; + marker2Long?: number; + initialLat?: number; + initialLong?: number; + zoom?: number; + commentCoords?: string; + commentInitialPosition?: string; + commentMarkerClicked?: string; + commentAddMarkers?: string; +} + +const { + marker1Label = "Tokyo Tower", + marker1Lat = 35.6586, + marker1Long = 139.7454, + marker2Label = "Sky Tree", + marker2Lat = 35.7101, + marker2Long = 139.8107, + initialLat = 35.6586, + initialLong = 139.7454, + zoom = 11.0, + commentCoords = "東京タワーとスカイツリーの座標", + commentInitialPosition = "カメラの初期位置", + commentMarkerClicked = "マーカーがクリックされました: ", + commentAddMarkers = "マーカーを追加" +} = Astro.props; + +const code = `import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.mapconductor.core.* +import com.mapconductor.googlemaps.GoogleMapView +import com.mapconductor.googlemaps.rememberGoogleMapViewState + +@Composable +fun MapWithMarkers(modifier: Modifier = Modifier) { + // ${commentCoords} + val marker1 = GeoPoint.fromLatLong(${marker1Lat}, ${marker1Long}) + val marker2 = GeoPoint.fromLatLong(${marker2Lat}, ${marker2Long}) + + // ${commentInitialPosition} + val initialCamera = MapCameraPosition( + position = GeoPoint.fromLatLong(${initialLat}, ${initialLong}), + zoom = ${zoom} + ) + + val mapViewState = rememberGoogleMapViewState( + cameraPosition = initialCamera + ) + val onMarkerClick: (MarkerState) -> Unit = { markerState -> + println("${commentMarkerClicked}\${markerState.extra}") + } + + GoogleMapView( + modifier = modifier.fillMaxSize(), + state = mapViewState + ) { + // ${commentAddMarkers} + Marker( + position = marker1, + icon = DefaultIcon(label = "${marker1Label}"), + extra = "marker1", + onClick = onMarkerClick + ) + + Marker( + position = marker2, + icon = DefaultIcon(label = "${marker2Label}"), + extra = "marker2", + onClick = onMarkerClick + ) + } +}`; +--- + + diff --git a/docs/src/components/get-started/MarkerClickInteraction.astro b/docs/src/components/get-started/MarkerClickInteraction.astro new file mode 100644 index 00000000..412799ca --- /dev/null +++ b/docs/src/components/get-started/MarkerClickInteraction.astro @@ -0,0 +1,52 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + marker1Label?: string; + marker1Lat?: number; + marker1Long?: number; + marker2Label?: string; + marker2Lat?: number; + marker2Long?: number; + commentMarkerClicked?: string; +} + +const { + marker1Label = "TT", + marker1Lat = 35.6586, + marker1Long = 139.7454, + marker2Label = "ST", + marker2Lat = 35.7101, + marker2Long = 139.8107, + commentMarkerClicked = "マーカーがクリックされたときの処理" +} = Astro.props; + +const code = `val marker1 = GeoPoint.fromLatLong(${marker1Lat}, ${marker1Long}) +val marker2 = GeoPoint.fromLatLong(${marker2Lat}, ${marker2Long}) + +GoogleMapView( + modifier = modifier.fillMaxSize(), + state = mapViewState +) { + Marker( + position = marker1, + icon = DefaultIcon(label = "${marker1Label}"), + extra = "marker1", + onClick = { markerState -> + // ${commentMarkerClicked} + markerState.animate(MarkerAnimation.Drop) + } + ) + Marker( + position = marker2, + icon = DefaultIcon(label = "${marker2Label}"), + extra = "marker2", + onClick = { markerState -> + // ${commentMarkerClicked} + markerState.animate(MarkerAnimation.Bounce) + } + ) +}`; +--- + + diff --git a/docs/src/components/get-started/MarkerCustomization.astro b/docs/src/components/get-started/MarkerCustomization.astro new file mode 100644 index 00000000..df5dd7f6 --- /dev/null +++ b/docs/src/components/get-started/MarkerCustomization.astro @@ -0,0 +1,30 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + label?: string; + lat?: number; + long?: number; + commentAnchorInfo?: string; +} + +const { + label = "TT", + lat = 35.6586, + long = 139.7454, + commentAnchorInfo = "x = 0.0(左)~1.0(右), y = 0.0(上)~1.0(下)" +} = Astro.props; + +const code = `Marker( + position = GeoPoint.fromLatLong(${lat}, ${long}), + icon = DefaultIcon( + label = "${label}", + backgroundColor = Color.Red, + textColor = Color.White + ), + extra = "tokyo_tower", + anchor = Offset(0.5f, 1.0f) // ${commentAnchorInfo} +)`; +--- + + diff --git a/docs/src/components/get-started/MyFirstMap.astro b/docs/src/components/get-started/MyFirstMap.astro new file mode 100644 index 00000000..93f2892a --- /dev/null +++ b/docs/src/components/get-started/MyFirstMap.astro @@ -0,0 +1,55 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + lat?: number; + long?: number; + zoom?: number; + commentTokyoCoords?: string; + commentInitialCamera?: string; + commentStateManagement?: string; + commentMapDisplay?: string; +} + +const { + lat = 35.6812, + long = 139.7671, + zoom = 12.0, + commentTokyoCoords = "東京の座標", + commentInitialCamera = "カメラの初期位置を設定", + commentStateManagement = "地図の状態を管理するstateオブジェクトを作成", + commentMapDisplay = "地図を表示" +} = Astro.props; + +const code = `import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.mapconductor.core.GeoPoint +import com.mapconductor.core.MapCameraPosition +import com.mapconductor.googlemaps.GoogleMapView +import com.mapconductor.googlemaps.rememberGoogleMapViewState + +@Composable +fun MyFirstMap(modifier: Modifier = Modifier) { + // ${commentTokyoCoords} + val tokyo = GeoPoint.fromLatLong(${lat}, ${long}) + + // ${commentInitialCamera} + val initialCamera = MapCameraPosition( + position = tokyo, + zoom = ${zoom} + ) + + // ${commentStateManagement} + val mapViewState = rememberGoogleMapViewState( + cameraPosition = initialCamera + ) + + // ${commentMapDisplay} + GoogleMapView( + modifier = modifier, + state = mapViewState + ) +}`; +--- + + diff --git a/docs/src/components/get-started/PolylineExample.astro b/docs/src/components/get-started/PolylineExample.astro new file mode 100644 index 00000000..e0c00b0e --- /dev/null +++ b/docs/src/components/get-started/PolylineExample.astro @@ -0,0 +1,48 @@ +--- +import { Code } from '@astrojs/starlight/components'; + +interface Props { + marker1Label?: string; + marker1Lat?: number; + marker1Long?: number; + marker2Label?: string; + marker2Lat?: number; + marker2Long?: number; + strokeWidth?: string; + commentMarker?: string; + commentDrawLine?: string; +} + +const { + marker1Label = "TT", + marker1Lat = 35.6586, + marker1Long = 139.7454, + marker2Label = "ST", + marker2Lat = 35.7101, + marker2Long = 139.8107, + strokeWidth = "5.dp", + commentMarker = "マーカー", + commentDrawLine = "2つのポイントを結ぶ線" +} = Astro.props; + +const code = `GoogleMapView( + modifier = modifier.fillMaxSize(), + state = mapViewState +) { + // ${commentMarker} + Marker(position = GeoPoint.fromLatLong(${marker1Lat}, ${marker1Long}), icon = DefaultIcon(label = "${marker1Label}")) + Marker(position = GeoPoint.fromLatLong(${marker2Lat}, ${marker2Long}), icon = DefaultIcon(label = "${marker2Label}")) + + // ${commentDrawLine} + Polyline( + points = listOf( + GeoPoint.fromLatLong(${marker1Lat}, ${marker1Long}), + GeoPoint.fromLatLong(${marker2Lat}, ${marker2Long}) + ), + strokeColor = Color.Red, + strokeWidth = ${strokeWidth} + ) +}`; +--- + + diff --git a/docs/src/components/get-started/SDKSwitchComparison.astro b/docs/src/components/get-started/SDKSwitchComparison.astro new file mode 100644 index 00000000..12817461 --- /dev/null +++ b/docs/src/components/get-started/SDKSwitchComparison.astro @@ -0,0 +1,59 @@ +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; +import { Code } from '@astrojs/starlight/components'; + +interface Props { + commentComponents?: string; + commentComponentsNoChange?: string; + beforeLabel?: string; + afterLabel?: string; +} + +const { + commentComponents = "マーカーやその他のコンポーネント", + commentComponentsNoChange = "マーカーやその他のコンポーネント(変更なし!)", + beforeLabel = "変更前 (Google Maps)", + afterLabel = "変更後 (Mapbox)" +} = Astro.props; + +const googleMapsCode = `import com.mapconductor.googlemaps.GoogleMapView +import com.mapconductor.googlemaps.rememberGoogleMapViewState + +@Composable +fun MyMap() { + val mapViewState = rememberGoogleMapViewState( + cameraPosition = initialCamera + ) + + GoogleMapView( + state = mapViewState + ) { + // ${commentComponents} + } +}`; + +const mapboxCode = `import com.mapconductor.mapbox.MapboxMapView +import com.mapconductor.mapbox.rememberMapboxViewState + +@Composable +fun MyMap() { + val mapViewState = rememberMapboxViewState( + cameraPosition = initialCamera + ) + + MapboxMapView( + state = mapViewState + ) { + // ${commentComponentsNoChange} + } +}`; +--- + + + + + + + + + diff --git a/docs/src/components/home/Hero.astro b/docs/src/components/home/Hero.astro index 21d52be6..a79d2018 100644 --- a/docs/src/components/home/Hero.astro +++ b/docs/src/components/home/Hero.astro @@ -23,28 +23,6 @@ const { title, subtitle, heroMessage } = Astro.props;