@smartnet360/svelte-components 0.0.104 → 0.0.106

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 ADDED
@@ -0,0 +1,75 @@
1
+ # RF Tool Components
2
+
3
+ Private SvelteKit component library for RF planning and network visualization tools.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @smartnet360/svelte-components
9
+ ```
10
+
11
+ ## Components
12
+
13
+ ### Core Components (`@smartnet360/svelte-components/core`)
14
+
15
+ | Component | Description |
16
+ |-----------|-------------|
17
+ | **Desktop** | Grid orchestrator for multi-panel layouts with component assignment |
18
+ | **Charts** | Plotly-based chart system with tabs/scrollspy modes |
19
+ | **CellTable** | Tabulator-based cell data table with grouping and filtering |
20
+ | **TreeView** | Hierarchical tree component for data navigation |
21
+ | **Settings** | Configuration panels and settings management |
22
+ | **CoverageMap** | Coverage visualization component |
23
+
24
+ ### Map Components
25
+
26
+ | Package | Description |
27
+ |---------|-------------|
28
+ | **map-v2** | Legacy map implementation |
29
+ | **map-v3** | Current map implementation with cell/site features |
30
+
31
+ ### Shared Utilities (`@smartnet360/svelte-components/shared`)
32
+
33
+ | Module | Description |
34
+ |--------|-------------|
35
+ | **demo** | Cell data generator with configurable presets (small/medium/large/xlarge) |
36
+ | **ResizableSplitPanel** | Draggable split panel component |
37
+
38
+ ## Development
39
+
40
+ ```bash
41
+ # Install dependencies
42
+ npm install
43
+
44
+ # Run dev server
45
+ npm run dev
46
+
47
+ # Type checking
48
+ npm run check
49
+
50
+ # Build library
51
+ npm run build
52
+
53
+ # Release (patch/minor/major)
54
+ npm run release:patch
55
+ ```
56
+
57
+ ## Demo Routes
58
+
59
+ Demo pages available at `/apps/demo/`:
60
+ - `/apps/demo/cell-table` - CellTable component
61
+ - `/apps/demo/charts` - Charts component
62
+ - `/apps/demo/desktop` - Desktop grid system
63
+
64
+ ## Tech Stack
65
+
66
+ - **Svelte 5** with runes (`$state`, `$derived`, `$effect`)
67
+ - **SvelteKit** library mode
68
+ - **TypeScript** first
69
+ - **Bootstrap 5** for styling
70
+ - **Plotly.js** for charts
71
+ - **Tabulator** for data tables
72
+
73
+ ## License
74
+
75
+ Private - SmartNet360
@@ -0,0 +1,101 @@
1
+ <script lang="ts">
2
+ import CellTablePanel from './CellTablePanel.svelte';
3
+ import type { CellTableGroupField, ColumnPreset, RowSelectionEvent } from './types';
4
+ import { generateCellsFromPreset, getGeneratorInfo, type GeneratorPreset } from '../../shared/demo';
5
+
6
+ let datasetSize: GeneratorPreset = $state('small');
7
+ let demoCells = $state(generateCellsFromPreset('small'));
8
+ let dataInfo = $derived(getGeneratorInfo(demoCells));
9
+
10
+ let groupBy: CellTableGroupField = $state('none');
11
+ let columnPreset: ColumnPreset = $state('default');
12
+
13
+ function handleSelectionChange(event: RowSelectionEvent) {
14
+ console.log('Selection changed:', event.ids);
15
+ }
16
+
17
+ function regenerateData() {
18
+ demoCells = generateCellsFromPreset(datasetSize);
19
+ }
20
+ </script>
21
+
22
+ <div class="cell-table-page vh-100 d-flex flex-column">
23
+ <!-- Simple header for demo controls only -->
24
+ <div class="demo-controls bg-light border-bottom px-3 py-2 d-flex align-items-center gap-3 flex-wrap">
25
+ <div class="input-group input-group-sm" style="width: auto;">
26
+ <span class="input-group-text">Dataset</span>
27
+ <select class="form-select" bind:value={datasetSize} onchange={regenerateData}>
28
+ <option value="small">Small (~300)</option>
29
+ <option value="medium">Medium (~3K)</option>
30
+ <option value="large">Large (~15K)</option>
31
+ <option value="xlarge">XLarge (~60K)</option>
32
+ </select>
33
+ </div>
34
+ <span class="badge bg-info">
35
+ {dataInfo.totalCells.toLocaleString()} cells | {dataInfo.totalSites} sites
36
+ </span>
37
+ <span class="badge bg-secondary d-none d-md-inline">
38
+ {Object.entries(dataInfo.techBreakdown).map(([k, v]) => `${k}: ${v}`).join(' | ')}
39
+ </span>
40
+ </div>
41
+
42
+ <!-- CellTablePanel with integrated sidebar -->
43
+ <div class="flex-grow-1 overflow-hidden">
44
+ <CellTablePanel
45
+ cells={demoCells}
46
+ bind:groupBy
47
+ bind:columnPreset
48
+ selectable={true}
49
+ multiSelect={true}
50
+ showToolbar={true}
51
+ showExport={true}
52
+ headerFilters={true}
53
+ showDetailsSidebar={true}
54
+ sidebarWidth={320}
55
+ title="Cell Data"
56
+ onselectionchange={handleSelectionChange}
57
+ >
58
+ {#snippet footer({ selectedRows, selectedCount })}
59
+ <div class="d-flex align-items-center justify-content-between">
60
+ <span class="text-muted small">
61
+ {#if selectedCount > 0}
62
+ {selectedCount} cell(s) selected
63
+ {:else}
64
+ Click a row to view details
65
+ {/if}
66
+ </span>
67
+ <div class="btn-group">
68
+ <button
69
+ type="button"
70
+ class="btn btn-sm btn-outline-primary"
71
+ disabled={selectedCount === 0}
72
+ onclick={() => console.log('Process:', selectedRows.map(r => r.id))}
73
+ >
74
+ <i class="bi bi-gear"></i>
75
+ <span class="d-none d-sm-inline ms-1">Process</span>
76
+ </button>
77
+ <button
78
+ type="button"
79
+ class="btn btn-sm btn-outline-secondary"
80
+ disabled={selectedCount === 0}
81
+ onclick={() => console.log('Export:', selectedRows.map(r => r.id))}
82
+ >
83
+ <i class="bi bi-download"></i>
84
+ <span class="d-none d-sm-inline ms-1">Export</span>
85
+ </button>
86
+ </div>
87
+ </div>
88
+ {/snippet}
89
+ </CellTablePanel>
90
+ </div>
91
+ </div>
92
+
93
+ <style>
94
+ .cell-table-page {
95
+ background: var(--bs-body-bg, #f8f9fa);
96
+ }
97
+
98
+ .demo-controls {
99
+ flex-shrink: 0;
100
+ }
101
+ </style>
@@ -0,0 +1,3 @@
1
+ declare const CellTableDemo: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type CellTableDemo = ReturnType<typeof CellTableDemo>;
3
+ export default CellTableDemo;
@@ -39,6 +39,12 @@
39
39
  headerFilters?: boolean;
40
40
  /** Panel title */
41
41
  title?: string;
42
+ /** Show details sidebar */
43
+ showDetailsSidebar?: boolean;
44
+ /** Sidebar width in pixels */
45
+ sidebarWidth?: number;
46
+ /** Bindable reference to table methods */
47
+ tableRef?: { redraw: () => void } | null;
42
48
  /** Row selection change event */
43
49
  onselectionchange?: (event: RowSelectionEvent) => void;
44
50
  /** Row click event */
@@ -49,6 +55,8 @@
49
55
  headerActions?: Snippet;
50
56
  /** Custom footer slot */
51
57
  footer?: Snippet<[{ selectedRows: CellData[]; selectedCount: number }]>;
58
+ /** Custom details sidebar content */
59
+ detailsContent?: Snippet<[{ cell: CellData | null; closeSidebar: () => void }]>;
52
60
  }
53
61
 
54
62
  let {
@@ -64,17 +72,32 @@
64
72
  statusColors,
65
73
  headerFilters = true,
66
74
  title = 'Cell Data',
75
+ showDetailsSidebar = false,
76
+ sidebarWidth = 320,
77
+ tableRef = $bindable(null),
67
78
  onselectionchange,
68
79
  onrowclick,
69
80
  onrowdblclick,
70
81
  headerActions,
71
- footer
82
+ footer,
83
+ detailsContent
72
84
  }: Props = $props();
73
85
 
74
86
  let cellTable: CellTable;
75
87
  let selectedCount = $state(0);
76
88
  let selectedRows = $state<CellData[]>([]);
77
89
  let filteredCount = $state(cells.length);
90
+ let sidebarOpen = $state(false);
91
+ let clickedCell: CellData | null = $state(null);
92
+
93
+ // Expose table methods via tableRef
94
+ $effect(() => {
95
+ if (cellTable) {
96
+ tableRef = {
97
+ redraw: () => cellTable?.redraw()
98
+ };
99
+ }
100
+ });
78
101
 
79
102
  function handleSelectionChange(event: RowSelectionEvent) {
80
103
  selectedCount = event.rows.length;
@@ -82,6 +105,15 @@
82
105
  onselectionchange?.(event);
83
106
  }
84
107
 
108
+ function handleRowClick(event: RowClickEvent) {
109
+ if (showDetailsSidebar) {
110
+ clickedCell = event.row;
111
+ sidebarOpen = true;
112
+ setTimeout(() => cellTable?.redraw(), 320);
113
+ }
114
+ onrowclick?.(event);
115
+ }
116
+
85
117
  function handleDataChange(event: DataChangeEvent) {
86
118
  filteredCount = event.filteredCount;
87
119
  }
@@ -106,6 +138,16 @@
106
138
  cellTable?.clearFilters();
107
139
  }
108
140
 
141
+ function toggleSidebar() {
142
+ sidebarOpen = !sidebarOpen;
143
+ setTimeout(() => cellTable?.redraw(), 320);
144
+ }
145
+
146
+ function closeSidebar() {
147
+ sidebarOpen = false;
148
+ setTimeout(() => cellTable?.redraw(), 320);
149
+ }
150
+
109
151
  // Expose table methods
110
152
  export function getSelectedRows(): CellData[] {
111
153
  return cellTable?.getSelectedRows() ?? [];
@@ -122,6 +164,11 @@
122
164
  export function redraw(): void {
123
165
  cellTable?.redraw();
124
166
  }
167
+
168
+ export function openSidebar(): void {
169
+ sidebarOpen = true;
170
+ setTimeout(() => cellTable?.redraw(), 320);
171
+ }
125
172
  </script>
126
173
 
127
174
  <div class="cell-table-panel d-flex flex-column" style:height>
@@ -131,11 +178,24 @@
131
178
  <i class="bi bi-table text-primary"></i>
132
179
  {title}
133
180
  </h6>
134
- {#if headerActions}
135
- <div class="header-actions">
136
- {@render headerActions()}
137
- </div>
138
- {/if}
181
+ <div class="d-flex align-items-center gap-2">
182
+ {#if headerActions}
183
+ <div class="header-actions">
184
+ {@render headerActions()}
185
+ </div>
186
+ {/if}
187
+ {#if showDetailsSidebar}
188
+ <button
189
+ class="btn btn-sm"
190
+ class:btn-outline-secondary={!sidebarOpen}
191
+ class:btn-secondary={sidebarOpen}
192
+ onclick={toggleSidebar}
193
+ title={sidebarOpen ? 'Hide details' : 'Show details'}
194
+ >
195
+ <i class="bi" class:bi-layout-sidebar-reverse={!sidebarOpen} class:bi-x-lg={sidebarOpen}></i>
196
+ </button>
197
+ {/if}
198
+ </div>
139
199
  </div>
140
200
 
141
201
  <!-- Toolbar -->
@@ -155,24 +215,132 @@
155
215
  />
156
216
  {/if}
157
217
 
158
- <!-- Table -->
159
- <div class="table-wrapper flex-grow-1">
160
- <CellTable
161
- bind:this={cellTable}
162
- {cells}
163
- {groupBy}
164
- {columnPreset}
165
- {selectable}
166
- {multiSelect}
167
- height="100%"
168
- {techColors}
169
- {statusColors}
170
- {headerFilters}
171
- onselectionchange={handleSelectionChange}
172
- ondatachange={handleDataChange}
173
- {onrowclick}
174
- {onrowdblclick}
175
- />
218
+ <!-- Main content with optional sidebar -->
219
+ <div class="content-area d-flex flex-grow-1 overflow-hidden">
220
+ <!-- Table -->
221
+ <div class="table-wrapper flex-grow-1 overflow-hidden">
222
+ <CellTable
223
+ bind:this={cellTable}
224
+ {cells}
225
+ {groupBy}
226
+ {columnPreset}
227
+ {selectable}
228
+ {multiSelect}
229
+ height="100%"
230
+ {techColors}
231
+ {statusColors}
232
+ {headerFilters}
233
+ onselectionchange={handleSelectionChange}
234
+ ondatachange={handleDataChange}
235
+ onrowclick={handleRowClick}
236
+ {onrowdblclick}
237
+ />
238
+ </div>
239
+
240
+ <!-- Details Sidebar -->
241
+ {#if showDetailsSidebar}
242
+ <aside
243
+ class="details-sidebar border-start bg-white overflow-auto"
244
+ class:open={sidebarOpen}
245
+ style:--sidebar-width="{sidebarWidth}px"
246
+ >
247
+ <div class="sidebar-content" style:width="{sidebarWidth}px">
248
+ <div class="d-flex align-items-center justify-content-between p-3 border-bottom bg-light sticky-top">
249
+ <h6 class="mb-0">
250
+ <i class="bi bi-info-circle text-primary"></i> Details
251
+ </h6>
252
+ <button
253
+ class="btn btn-sm btn-outline-secondary"
254
+ onclick={closeSidebar}
255
+ title="Close"
256
+ >
257
+ <i class="bi bi-x-lg"></i>
258
+ </button>
259
+ </div>
260
+
261
+ <div class="p-3">
262
+ {#if detailsContent}
263
+ {@render detailsContent({ cell: clickedCell, closeSidebar })}
264
+ {:else if clickedCell}
265
+ <!-- Default details view -->
266
+ <dl class="row mb-0 small">
267
+ <dt class="col-5 text-muted">ID</dt>
268
+ <dd class="col-7"><code class="text-primary">{clickedCell.id}</code></dd>
269
+
270
+ <dt class="col-5 text-muted">Cell Name</dt>
271
+ <dd class="col-7 fw-medium">{clickedCell.cellName}</dd>
272
+
273
+ <dt class="col-5 text-muted">Site</dt>
274
+ <dd class="col-7">{clickedCell.siteId}</dd>
275
+
276
+ <dt class="col-5 text-muted">Technology</dt>
277
+ <dd class="col-7">
278
+ <span class="badge bg-secondary">{clickedCell.tech}</span>
279
+ </dd>
280
+
281
+ <dt class="col-5 text-muted">Band</dt>
282
+ <dd class="col-7">
283
+ <span class="badge bg-info">{clickedCell.fband}</span>
284
+ </dd>
285
+
286
+ <dt class="col-5 text-muted">Frequency</dt>
287
+ <dd class="col-7">{clickedCell.frq} MHz</dd>
288
+
289
+ <dt class="col-5 text-muted">Status</dt>
290
+ <dd class="col-7">
291
+ <span class="badge bg-success">{clickedCell.status.replace(/_/g, ' ')}</span>
292
+ </dd>
293
+
294
+ <dt class="col-12 text-muted mt-2 mb-1 border-top pt-2">Physical</dt>
295
+
296
+ <dt class="col-5 text-muted">Azimuth</dt>
297
+ <dd class="col-7">{clickedCell.azimuth}°</dd>
298
+
299
+ <dt class="col-5 text-muted">Height</dt>
300
+ <dd class="col-7">{clickedCell.height}m</dd>
301
+
302
+ <dt class="col-5 text-muted">Beamwidth</dt>
303
+ <dd class="col-7">{clickedCell.beamwidth}°</dd>
304
+
305
+ <dt class="col-5 text-muted">E-Tilt</dt>
306
+ <dd class="col-7">{clickedCell.electricalTilt}°</dd>
307
+
308
+ <dt class="col-5 text-muted">Antenna</dt>
309
+ <dd class="col-7 text-truncate" title={clickedCell.antenna}>
310
+ {clickedCell.antenna}
311
+ </dd>
312
+
313
+ <dt class="col-12 text-muted mt-2 mb-1 border-top pt-2">Location</dt>
314
+
315
+ <dt class="col-5 text-muted">Latitude</dt>
316
+ <dd class="col-7">{clickedCell.latitude.toFixed(6)}</dd>
317
+
318
+ <dt class="col-5 text-muted">Longitude</dt>
319
+ <dd class="col-7">{clickedCell.longitude.toFixed(6)}</dd>
320
+
321
+ <dt class="col-12 text-muted mt-2 mb-1 border-top pt-2">Planning</dt>
322
+
323
+ <dt class="col-5 text-muted">Planner</dt>
324
+ <dd class="col-7">{clickedCell.planner}</dd>
325
+
326
+ <dt class="col-5 text-muted">On Air</dt>
327
+ <dd class="col-7">{clickedCell.onAirDate}</dd>
328
+
329
+ {#if clickedCell.comment}
330
+ <dt class="col-5 text-muted">Comment</dt>
331
+ <dd class="col-7 fst-italic">{clickedCell.comment}</dd>
332
+ {/if}
333
+ </dl>
334
+ {:else}
335
+ <div class="text-center text-muted py-5">
336
+ <i class="bi bi-hand-index fs-1 opacity-50"></i>
337
+ <p class="mt-2 mb-0">Click a row to see details</p>
338
+ </div>
339
+ {/if}
340
+ </div>
341
+ </div>
342
+ </aside>
343
+ {/if}
176
344
  </div>
177
345
 
178
346
  <!-- Footer -->
@@ -200,9 +368,26 @@
200
368
  color: var(--bs-body-color, #212529);
201
369
  }
202
370
 
371
+ .content-area {
372
+ min-height: 0;
373
+ }
374
+
203
375
  .table-wrapper {
204
376
  min-height: 0;
205
- overflow: hidden;
377
+ transition: all 0.3s ease;
378
+ }
379
+
380
+ .details-sidebar {
381
+ width: 0;
382
+ min-width: 0;
383
+ opacity: 0;
384
+ transition: width 0.3s ease, opacity 0.3s ease, min-width 0.3s ease;
385
+ }
386
+
387
+ .details-sidebar.open {
388
+ width: var(--sidebar-width, 320px);
389
+ min-width: var(--sidebar-width, 320px);
390
+ opacity: 1;
206
391
  }
207
392
 
208
393
  .panel-footer {
@@ -25,6 +25,14 @@ interface Props {
25
25
  headerFilters?: boolean;
26
26
  /** Panel title */
27
27
  title?: string;
28
+ /** Show details sidebar */
29
+ showDetailsSidebar?: boolean;
30
+ /** Sidebar width in pixels */
31
+ sidebarWidth?: number;
32
+ /** Bindable reference to table methods */
33
+ tableRef?: {
34
+ redraw: () => void;
35
+ } | null;
28
36
  /** Row selection change event */
29
37
  onselectionchange?: (event: RowSelectionEvent) => void;
30
38
  /** Row click event */
@@ -38,12 +46,18 @@ interface Props {
38
46
  selectedRows: CellData[];
39
47
  selectedCount: number;
40
48
  }]>;
49
+ /** Custom details sidebar content */
50
+ detailsContent?: Snippet<[{
51
+ cell: CellData | null;
52
+ closeSidebar: () => void;
53
+ }]>;
41
54
  }
42
55
  declare const CellTablePanel: import("svelte").Component<Props, {
43
56
  getSelectedRows: () => CellData[];
44
57
  clearSelection: () => void;
45
58
  scrollToRow: (id: string) => void;
46
59
  redraw: () => void;
47
- }, "groupBy" | "columnPreset">;
60
+ openSidebar: () => void;
61
+ }, "groupBy" | "columnPreset" | "tableRef">;
48
62
  type CellTablePanel = ReturnType<typeof CellTablePanel>;
49
63
  export default CellTablePanel;
@@ -6,5 +6,7 @@
6
6
  export { default as CellTable } from './CellTable.svelte';
7
7
  export { default as CellTableToolbar } from './CellTableToolbar.svelte';
8
8
  export { default as CellTablePanel } from './CellTablePanel.svelte';
9
+ export { default as CellTableDemo } from './CellTableDemo.svelte';
10
+ export { generateCells, generateCellsFromPreset, getGeneratorInfo, GENERATOR_PRESETS, type CellGeneratorConfig, type GeneratorPreset } from '../../shared/demo';
9
11
  export type { CellData, CellTableGroupField, ColumnPreset, ColumnVisibility, TechColorMap, StatusColorMap, CellTableProps, RowSelectionEvent, RowClickEvent, RowDblClickEvent, DataChangeEvent, CellTableColumn, ColumnGroups } from './types';
10
12
  export { DEFAULT_TECH_COLORS, DEFAULT_STATUS_COLORS, FBAND_COLORS, COLUMN_GROUPS, getAllColumns, getColumnsForPreset, getGroupHeaderFormatter, createTechFormatter, createStatusFormatter, createFbandFormatter, numberFormatter, coordinateFormatter, azimuthFormatter, heightFormatter } from './column-config';
@@ -7,5 +7,10 @@
7
7
  export { default as CellTable } from './CellTable.svelte';
8
8
  export { default as CellTableToolbar } from './CellTableToolbar.svelte';
9
9
  export { default as CellTablePanel } from './CellTablePanel.svelte';
10
+ export { default as CellTableDemo } from './CellTableDemo.svelte';
11
+ // Re-export shared demo data utilities for convenience
12
+ // Note: Cell type is NOT re-exported here to avoid conflicts with map-v2
13
+ // Import Cell from '$lib/shared/demo' or '@smartnet360/svelte-components' directly
14
+ export { generateCells, generateCellsFromPreset, getGeneratorInfo, GENERATOR_PRESETS } from '../../shared/demo';
10
15
  // Configuration utilities
11
16
  export { DEFAULT_TECH_COLORS, DEFAULT_STATUS_COLORS, FBAND_COLORS, COLUMN_GROUPS, getAllColumns, getColumnsForPreset, getGroupHeaderFormatter, createTechFormatter, createStatusFormatter, createFbandFormatter, numberFormatter, coordinateFormatter, azimuthFormatter, heightFormatter } from './column-config';
@@ -4,56 +4,15 @@
4
4
  * Types for the Tabulator-based cell data table component
5
5
  */
6
6
  import type { ColumnDefinition, Options } from 'tabulator-tables';
7
+ import type { Cell, CellGroupingField } from '../../shared/demo';
7
8
  /**
8
- * Cell data model - represents a radio cell/sector
9
- * Imported from map-v3 cells feature for consistency
9
+ * Cell data model - re-exported from shared for convenience
10
10
  */
11
- export interface CellData {
12
- id: string;
13
- txId: string;
14
- cellID: string;
15
- cellID2G: string;
16
- cellName: string;
17
- siteId: string;
18
- tech: string;
19
- fband: string;
20
- frq: string;
21
- type: string;
22
- status: string;
23
- onAirDate: string;
24
- bcch: number;
25
- ctrlid: string;
26
- dlEarfn: number;
27
- antenna: string;
28
- azimuth: number;
29
- height: number;
30
- electricalTilt: string;
31
- beamwidth: number;
32
- latitude: number;
33
- longitude: number;
34
- dx: number;
35
- dy: number;
36
- siteLatitude: number;
37
- siteLongitude: number;
38
- comment: string;
39
- planner: string;
40
- atollETP: number;
41
- atollPW: number;
42
- atollRS: number;
43
- atollBW: number;
44
- cellId3: string;
45
- nwtP1: number;
46
- nwtP2: number;
47
- pci1: number;
48
- nwtRS: number;
49
- nwtBW: number;
50
- other?: Record<string, unknown>;
51
- customSubgroup: string;
52
- }
11
+ export type CellData = Cell;
53
12
  /**
54
- * Available grouping fields for the table
13
+ * Available grouping fields for the table - extends shared type with 'none' option
55
14
  */
56
- export type CellTableGroupField = 'tech' | 'fband' | 'frq' | 'status' | 'siteId' | 'none';
15
+ export type CellTableGroupField = CellGroupingField | 'none';
57
16
  /**
58
17
  * Column preset configurations
59
18
  */
@@ -1,14 +1,18 @@
1
1
  /**
2
- * Demo Cell Data
2
+ * Demo Cell Data - Map V3
3
3
  *
4
- * 100 sites across San Francisco Bay Area
5
- * Each site has 3 sectors (azimuths: 0°, 120°, 240°)
6
- * Each sector has 12 cells (all tech-band combinations)
7
- * Total: 100 sites × 3 sectors × 12 tech-bands = 3,600 cells
8
- */
9
- import type { Cell } from '../features/cells/types';
10
- /**
11
- * Generate demo cells with varied density patterns in circular distribution
12
- * Creates density zones radiating from center with random placement
4
+ * Uses the shared cell generator to create demo data.
5
+ * Default: 2000 sites, ~60k cells across Budapest area.
6
+ *
7
+ * Structure:
8
+ * - CellName format: 7-digit numeric (e.g., "1000141")
9
+ * - Format: SSSS (site) + S (sector 1-3) + BB (band 41-51)
10
+ * - Site ID range: 1000-2999
11
+ * - Example Site 1000:
12
+ * - Sector 1 (0°): 1000141-1000151 (11 bands)
13
+ * - Sector 2 (120°): 1000241-1000251 (11 bands)
14
+ * - Sector 3 (240°): 1000341-1000351 (11 bands)
13
15
  */
16
+ import { type Cell } from '../../shared/demo';
14
17
  export declare const demoCells: Cell[];
18
+ export type { Cell } from '../../shared/demo';