footprint-globe 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,69 @@
1
- # Temporary Holding Version
1
+ # footprint-globe
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ 足迹地球核心引擎。3D 地球,无 token,可嵌入。
4
+
5
+ [![npm](https://img.shields.io/npm/v/footprint-globe.svg)](https://www.npmjs.com/package/footprint-globe)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## 安装
9
+
10
+ ```bash
11
+ npm i footprint-globe maplibre-gl
12
+ ```
13
+
14
+ `maplibre-gl` 是 peer dependency。
15
+
16
+ ## 用法
17
+
18
+ ```ts
19
+ import { FootprintGlobe } from 'footprint-globe';
20
+ import maplibregl from 'maplibre-gl';
21
+ import 'maplibre-gl/dist/maplibre-gl.css';
22
+ import 'footprint-globe/dist/footprint-globe.css';
23
+
24
+ const globe = new FootprintGlobe(document.getElementById('globe')!, {
25
+ config: {
26
+ version: 1,
27
+ categories: [
28
+ {
29
+ id: 'travel',
30
+ label: '旅行',
31
+ color: '#f97316',
32
+ pins: [{ name: '东京', coords: [139.759, 35.682] }],
33
+ },
34
+ ],
35
+ },
36
+ maplibre: maplibregl,
37
+ });
38
+
39
+ // globe.update({ config: { theme: 'dark' } });
40
+ // globe.destroy();
41
+ ```
42
+
43
+ ## 导出
44
+
45
+ - 类:`FootprintGlobe`
46
+ - 工具:`validateConfig` / `normalizeConfig` / `loadData` / `parseCsv` / `parseGeoJson`
47
+ - 错误:`FootprintError` / `isFootprintError`
48
+ - 类型:`FootprintConfig` / `Category` / `Pin` / `RenderConfig` / `FootprintGlobeOptions` 等
49
+ - 常量:`DEFAULT_STYLE` / `DEFAULT_CENTER` / `DEFAULT_ZOOM` / `LIMITS` 等
50
+
51
+ ## 特性
52
+
53
+ - 3D 地球(globe 投影)
54
+ - 多分类标记、动态图例、单例弹窗
55
+ - 配置协议 v1
56
+ - 数据格式:JSON / CSV / GeoJSON
57
+ - 隐私模式(坐标模糊、仅城市)
58
+ - 优雅降级(WebGL 不可用时列表视图)
59
+ - 事件:`ready` / `error` / `marker:click`
60
+
61
+ ## 文档
62
+
63
+ - [完整文档](https://footprint-studio.pages.dev/)
64
+ - [API](https://footprint-studio.pages.dev/api/footprint-globe)
65
+ - [配置协议](https://footprint-studio.pages.dev/guide/config-protocol)
66
+
67
+ ## 许可
68
+
69
+ MIT © 2025 Footprint Studio
@@ -0,0 +1,178 @@
1
+ /* ============================================================
2
+ * 足迹地球 · 组件样式
3
+ * 契约依据:ADR-0001 决策 4、PRD v1.1 §7.1
4
+ * 类名前缀:footprint-
5
+ * CSS 变量前缀:--fp-
6
+ * ============================================================ */
7
+
8
+ :root {
9
+ /* 尺寸 */
10
+ --fp-marker-size: 8px;
11
+ --fp-marker-hover-scale: 1.15;
12
+ --fp-globe-height: 400px;
13
+ --fp-globe-radius: 12px;
14
+
15
+ /* 颜色 */
16
+ --fp-marker-color: #2563eb;
17
+ --fp-marker-border: #fff;
18
+ --fp-globe-bg: #eef2f7;
19
+ --fp-legend-bg: rgba(255, 255, 255, 0.9);
20
+ --fp-legend-color: #111827;
21
+
22
+ /* 阴影 */
23
+ --fp-marker-shadow: 0 0 0 4px rgba(17, 24, 39, 0.08), 0 1px 3px rgba(0, 0, 0, 0.25);
24
+ --fp-legend-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
25
+
26
+ /* 布局 */
27
+ --fp-legend-radius: 9999px;
28
+ --fp-legend-gap: 0.75rem;
29
+ }
30
+
31
+ /* 暗色主题覆盖 */
32
+ [data-fp-theme='dark'] {
33
+ --fp-globe-bg: #111827;
34
+ --fp-legend-bg: rgba(17, 24, 39, 0.85);
35
+ --fp-legend-color: #f9fafb;
36
+ --fp-marker-border: #111827;
37
+ }
38
+
39
+ /* ===== 容器 ===== */
40
+ .footprint-globe {
41
+ width: 100%;
42
+ min-height: var(--fp-globe-height);
43
+ border-radius: var(--fp-globe-radius);
44
+ overflow: hidden;
45
+ background: var(--fp-globe-bg);
46
+ position: relative;
47
+ }
48
+
49
+ /* ===== 标记 ===== */
50
+ .footprint-marker {
51
+ width: var(--fp-marker-size);
52
+ height: var(--fp-marker-size);
53
+ border-radius: 9999px;
54
+ border: 1px solid var(--fp-marker-border);
55
+ background: var(--fp-marker-color);
56
+ box-shadow: var(--fp-marker-shadow);
57
+ cursor: pointer;
58
+ padding: 0;
59
+ margin: 0;
60
+ display: block;
61
+ transition:
62
+ transform 120ms ease,
63
+ box-shadow 120ms ease;
64
+ appearance: none;
65
+ -webkit-appearance: none;
66
+ }
67
+
68
+ .footprint-marker:hover,
69
+ .footprint-marker:focus-visible {
70
+ transform: scale(var(--fp-marker-hover-scale));
71
+ outline: none;
72
+ }
73
+
74
+ .footprint-marker:focus-visible {
75
+ box-shadow:
76
+ 0 0 0 2px var(--fp-marker-border),
77
+ 0 0 0 6px var(--fp-marker-color);
78
+ }
79
+
80
+ /* ===== 图例 ===== */
81
+ .footprint-legend {
82
+ position: absolute;
83
+ right: 12px;
84
+ bottom: 12px;
85
+ display: flex;
86
+ gap: var(--fp-legend-gap);
87
+ align-items: center;
88
+ padding: 0.5rem 0.75rem;
89
+ border-radius: var(--fp-legend-radius);
90
+ background: var(--fp-legend-bg);
91
+ box-shadow: var(--fp-legend-shadow);
92
+ backdrop-filter: blur(6px);
93
+ color: var(--fp-legend-color);
94
+ font-size: 0.85rem;
95
+ line-height: 1.1;
96
+ z-index: 1;
97
+ }
98
+
99
+ .footprint-legend__item {
100
+ display: inline-flex;
101
+ align-items: center;
102
+ gap: 0.35rem;
103
+ white-space: nowrap;
104
+ }
105
+
106
+ .footprint-legend__dot {
107
+ width: 10px;
108
+ height: 10px;
109
+ border-radius: 9999px;
110
+ display: inline-block;
111
+ border: 2px solid var(--fp-marker-border);
112
+ box-shadow: 0 0 0 2px rgba(17, 24, 39, 0.08);
113
+ background: var(--fp-marker-color);
114
+ }
115
+
116
+ /* ===== 降级列表 ===== */
117
+ .footprint-list {
118
+ padding: 1rem 1.25rem;
119
+ background: var(--fp-globe-bg);
120
+ border-radius: var(--fp-globe-radius);
121
+ color: var(--fp-legend-color);
122
+ font-size: 0.95rem;
123
+ }
124
+
125
+ .footprint-list__notice {
126
+ margin: 0 0 1rem;
127
+ padding: 0.6rem 0.8rem;
128
+ border-radius: 8px;
129
+ background: rgba(0, 0, 0, 0.05);
130
+ font-size: 0.85rem;
131
+ color: var(--fp-legend-color);
132
+ }
133
+
134
+ .footprint-list__group {
135
+ margin-bottom: 1rem;
136
+ }
137
+
138
+ .footprint-list__heading {
139
+ display: flex;
140
+ align-items: center;
141
+ gap: 0.5rem;
142
+ margin: 0 0 0.5rem;
143
+ font-size: 0.95rem;
144
+ font-weight: 600;
145
+ }
146
+
147
+ .footprint-list__items {
148
+ margin: 0;
149
+ padding-left: 1.4rem;
150
+ list-style: disc;
151
+ }
152
+
153
+ .footprint-list__item {
154
+ margin: 0.2rem 0;
155
+ line-height: 1.5;
156
+ }
157
+
158
+ /* ===== 响应式 ===== */
159
+ @media (max-width: 768px) {
160
+ .footprint-globe {
161
+ min-height: 300px;
162
+ }
163
+ .footprint-legend {
164
+ font-size: 0.78rem;
165
+ padding: 0.4rem 0.6rem;
166
+ gap: 0.5rem;
167
+ }
168
+ }
169
+
170
+ /* ===== 兼容别名(一个 minor 版本后移除) ===== */
171
+ .mapbox-globe {
172
+ width: 100%;
173
+ min-height: var(--fp-globe-height);
174
+ border-radius: var(--fp-globe-radius);
175
+ overflow: hidden;
176
+ background: var(--fp-globe-bg);
177
+ position: relative;
178
+ }