@ifc-lite/viewer 1.17.4 → 1.17.6
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/.turbo/turbo-build.log +16 -16
- package/.turbo/turbo-typecheck.log +1 -1
- package/CHANGELOG.md +117 -0
- package/DESKTOP_CONTRACT_VERSION +1 -1
- package/dist/assets/{basketViewActivator-BmnNtVfZ.js → basketViewActivator-86rgogji.js} +1 -1
- package/dist/assets/drawing-2d-DoxKMqbO.js +257 -0
- package/dist/assets/{exporters-ChAtBmlj.js → exporters-CcPS9MK5.js} +2274 -2227
- package/dist/assets/{geometry.worker-BQ0rzNo-.js → geometry.worker-BFUYA08u.js} +1 -1
- package/dist/assets/ids-DQ5jY0E8.js +1 -0
- package/dist/assets/ifc-lite_bg-BINvzoCP.wasm +0 -0
- package/dist/assets/{index-Co8E2-FE.js → index-Bfms9I4A.js} +35160 -33084
- package/dist/assets/index-_bfZsDCC.css +1 -0
- package/dist/assets/{native-bridge-BRvbckFQ.js → native-bridge-DUyLCMZS.js} +104 -104
- package/dist/assets/{sandbox-DZiNLNMk.js → sandbox-C8575tul.js} +4340 -4322
- package/dist/assets/{server-client-BV8zHZ7Y.js → server-client-BuZK7OST.js} +1 -1
- package/dist/assets/{wasm-bridge-g01g7T9b.js → wasm-bridge-JsqEGDV8.js} +1 -1
- package/dist/index.html +8 -7
- package/index.html +1 -0
- package/package.json +7 -7
- package/src/App.tsx +16 -2
- package/src/components/viewer/CesiumOverlay.tsx +62 -19
- package/src/components/viewer/ChatPanel.tsx +195 -91
- package/src/components/viewer/MainToolbar.tsx +4 -3
- package/src/components/viewer/PropertiesPanel.tsx +16 -2
- package/src/components/viewer/SettingsPage.tsx +252 -101
- package/src/components/viewer/ThemeSwitch.tsx +63 -7
- package/src/components/viewer/ViewerLayout.tsx +1 -0
- package/src/components/viewer/Viewport.tsx +14 -2
- package/src/components/viewer/ViewportContainer.tsx +49 -64
- package/src/components/viewer/ViewportOverlays.tsx +5 -2
- package/src/components/viewer/bcf/BCFTopicDetail.tsx +4 -4
- package/src/components/viewer/chat/ModelSelector.tsx +90 -54
- package/src/components/viewer/properties/GeoreferencingPanel.tsx +113 -51
- package/src/components/viewer/properties/LocationMap.tsx +9 -7
- package/src/components/viewer/properties/ModelMetadataPanel.tsx +1 -1
- package/src/components/viewer/tools/SectionCapControls.tsx +237 -0
- package/src/components/viewer/tools/SectionPanel.tsx +39 -18
- package/src/components/viewer/useAnimationLoop.ts +9 -1
- package/src/components/viewer/useRenderUpdates.ts +1 -1
- package/src/hooks/ids/idsDataAccessor.ts +60 -24
- package/src/hooks/ingest/viewerModelIngest.ts +7 -2
- package/src/hooks/useIfcFederation.ts +326 -71
- package/src/hooks/useIfcLoader.ts +1 -0
- package/src/hooks/useViewControls.ts +13 -5
- package/src/index.css +484 -10
- package/src/lib/desktop-entitlement.ts +2 -4
- package/src/lib/geo/cesium-bridge.ts +15 -7
- package/src/lib/geo/effective-georef.test.ts +73 -0
- package/src/lib/geo/effective-georef.ts +111 -0
- package/src/lib/geo/reproject.ts +105 -19
- package/src/lib/llm/byok-guard.test.ts +77 -0
- package/src/lib/llm/byok-guard.ts +39 -0
- package/src/lib/llm/free-models.test.ts +0 -6
- package/src/lib/llm/models.ts +104 -42
- package/src/lib/llm/stream-client.ts +74 -110
- package/src/lib/llm/stream-direct.test.ts +130 -0
- package/src/lib/llm/stream-direct.ts +316 -0
- package/src/lib/llm/types.ts +14 -2
- package/src/main.tsx +1 -10
- package/src/services/api-keys.ts +73 -0
- package/src/store/constants.ts +20 -2
- package/src/store/index.ts +12 -5
- package/src/store/slices/cesiumSlice.ts +5 -0
- package/src/store/slices/chatSlice.test.ts +6 -76
- package/src/store/slices/chatSlice.ts +17 -58
- package/src/store/slices/sectionSlice.test.ts +87 -7
- package/src/store/slices/sectionSlice.ts +151 -5
- package/src/store/slices/uiSlice.ts +28 -5
- package/src/store/types.ts +26 -0
- package/src/utils/nativeSpatialDataStore.ts +4 -1
- package/src/utils/viewportUtils.ts +7 -2
- package/src/vite-env.d.ts +0 -4
- package/dist/assets/drawing-2d-gWfpdfYe.js +0 -257
- package/dist/assets/ids-B4jTqB1O.js +0 -1
- package/dist/assets/ifc-lite_bg-BX4E7TX8.wasm +0 -0
- package/dist/assets/index-DckuDqlv.css +0 -1
- package/src/components/viewer/UpgradePage.tsx +0 -71
- package/src/lib/desktop/ClerkDesktopEntitlementSync.tsx +0 -175
- package/src/lib/llm/ClerkChatSync.tsx +0 -74
- package/src/lib/llm/clerk-auth.ts +0 -62
package/src/index.css
CHANGED
|
@@ -412,6 +412,490 @@ body {
|
|
|
412
412
|
background-color: rgba(115, 218, 202, 0.05) !important;
|
|
413
413
|
}
|
|
414
414
|
|
|
415
|
+
/* ═══════════════════════════════════════════════════════════════════════════
|
|
416
|
+
COLORFUL MODE — Brutalist Aurora
|
|
417
|
+
Shift+click the toggle. The same sharp, functional, dense UI — but the
|
|
418
|
+
sky opened up. An aurora gradient behind the 3D scene, frosted-glass
|
|
419
|
+
panels, and the full Tokyo Night accent palette in its natural places.
|
|
420
|
+
No decorative borders. No gradient buttons. Just atmosphere.
|
|
421
|
+
═══════════════════════════════════════════════════════════════════════════ */
|
|
422
|
+
|
|
423
|
+
@custom-variant colorful (&:where(.colorful, .colorful *));
|
|
424
|
+
|
|
425
|
+
.colorful {
|
|
426
|
+
/* Tokyo Night accent palette — used only where colour already exists */
|
|
427
|
+
--cf-blue: #7aa2f7;
|
|
428
|
+
--cf-cyan: #7dcfff;
|
|
429
|
+
--cf-teal: #73daca;
|
|
430
|
+
--cf-magenta: #bb9af7;
|
|
431
|
+
--cf-purple: #9d7cd8;
|
|
432
|
+
--cf-orange: #ff9e64;
|
|
433
|
+
--cf-pink: #f7768e;
|
|
434
|
+
--cf-green: #9ece6a;
|
|
435
|
+
--cf-yellow: #e0af68;
|
|
436
|
+
|
|
437
|
+
/* Glass */
|
|
438
|
+
--cf-glass: rgba(255, 255, 255, 0.48);
|
|
439
|
+
--cf-glass-strong: rgba(255, 255, 255, 0.68);
|
|
440
|
+
|
|
441
|
+
/* ── Semantic tokens ── */
|
|
442
|
+
--color-background: #e0e6f0 !important;
|
|
443
|
+
--color-foreground: #1a1b2e !important;
|
|
444
|
+
--color-card: var(--cf-glass) !important;
|
|
445
|
+
--color-card-foreground: #1a1b2e !important;
|
|
446
|
+
--color-popover: var(--cf-glass-strong) !important;
|
|
447
|
+
--color-popover-foreground: #1a1b2e !important;
|
|
448
|
+
--color-primary: var(--cf-purple) !important;
|
|
449
|
+
--color-primary-foreground: #fff !important;
|
|
450
|
+
--color-secondary: rgba(157, 124, 216, 0.10) !important;
|
|
451
|
+
--color-secondary-foreground: #2e3050 !important;
|
|
452
|
+
--color-muted: rgba(0, 0, 0, 0.04) !important;
|
|
453
|
+
--color-muted-foreground: #555b78 !important;
|
|
454
|
+
--color-accent: rgba(157, 124, 216, 0.10) !important;
|
|
455
|
+
--color-accent-foreground: #2e3050 !important;
|
|
456
|
+
--color-destructive: var(--cf-pink) !important;
|
|
457
|
+
--color-destructive-foreground: #fff !important;
|
|
458
|
+
/* Borders: neutral, semi-transparent — NOT coloured */
|
|
459
|
+
--color-border: rgba(0, 0, 0, 0.10) !important;
|
|
460
|
+
--color-input: rgba(0, 0, 0, 0.06) !important;
|
|
461
|
+
--color-ring: var(--cf-purple) !important;
|
|
462
|
+
|
|
463
|
+
/* Hierarchy — lavender tints */
|
|
464
|
+
--hierarchy-selected-bg: rgba(157, 124, 216, 0.12);
|
|
465
|
+
--hierarchy-selected-text: #1a1b2e;
|
|
466
|
+
--hierarchy-text: #40445e;
|
|
467
|
+
--hierarchy-hover-bg: rgba(200, 195, 230, 0.15);
|
|
468
|
+
|
|
469
|
+
/* Tabs — warm peach undertone */
|
|
470
|
+
--tabs-bg: rgba(235, 215, 195, 0.25);
|
|
471
|
+
--tabs-border: rgba(0, 0, 0, 0.08);
|
|
472
|
+
--tab-text: #555b78;
|
|
473
|
+
--tab-active-bg: rgba(245, 230, 210, 0.55);
|
|
474
|
+
--tab-active-text: #1a1b2e;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/* ── Page background ── */
|
|
478
|
+
.colorful body,
|
|
479
|
+
.colorful #root {
|
|
480
|
+
background: #dde3f0 !important;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/* ── Toolbar: cool violet-tinted glass ── */
|
|
484
|
+
.colorful .border-b.bg-white,
|
|
485
|
+
.colorful .border-b.dark\:bg-black {
|
|
486
|
+
background: rgba(230, 225, 245, 0.60) !important;
|
|
487
|
+
backdrop-filter: blur(20px) saturate(1.5) !important;
|
|
488
|
+
-webkit-backdrop-filter: blur(20px) saturate(1.5) !important;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/* ── Panels & cards: frosted glass (neutral base) ── */
|
|
492
|
+
.colorful .bg-white,
|
|
493
|
+
.colorful .bg-card,
|
|
494
|
+
.colorful .bg-background {
|
|
495
|
+
background: var(--cf-glass) !important;
|
|
496
|
+
backdrop-filter: blur(16px) saturate(1.3) !important;
|
|
497
|
+
-webkit-backdrop-filter: blur(16px) saturate(1.3) !important;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
.colorful .bg-zinc-50,
|
|
501
|
+
.colorful .bg-zinc-100 {
|
|
502
|
+
background-color: rgba(255, 255, 255, 0.25) !important;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
.colorful .bg-zinc-900,
|
|
506
|
+
.colorful .bg-zinc-950,
|
|
507
|
+
.colorful .bg-black {
|
|
508
|
+
background: var(--cf-glass) !important;
|
|
509
|
+
backdrop-filter: blur(16px) saturate(1.3) !important;
|
|
510
|
+
-webkit-backdrop-filter: blur(16px) saturate(1.3) !important;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/* ── Tinted glass per panel — colour echoes the aurora ── */
|
|
514
|
+
|
|
515
|
+
/* Left panel: cool lavender tint (echoes aurora top) */
|
|
516
|
+
.colorful .panel-container:first-of-type,
|
|
517
|
+
.colorful [id="left-panel"] > .panel-container,
|
|
518
|
+
.colorful [id="left-panel"] > div {
|
|
519
|
+
background: rgba(200, 195, 230, 0.38) !important;
|
|
520
|
+
backdrop-filter: blur(16px) saturate(1.4) !important;
|
|
521
|
+
-webkit-backdrop-filter: blur(16px) saturate(1.4) !important;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/* Right panel: warm peach/amber tint (echoes aurora bottom) */
|
|
525
|
+
.colorful [id="right-panel"] > .panel-container,
|
|
526
|
+
.colorful [id="right-panel"] > div {
|
|
527
|
+
background: rgba(235, 215, 195, 0.40) !important;
|
|
528
|
+
backdrop-filter: blur(16px) saturate(1.4) !important;
|
|
529
|
+
-webkit-backdrop-filter: blur(16px) saturate(1.4) !important;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/* Resize handles: thin, tinted */
|
|
533
|
+
.colorful [data-panel-group-direction="horizontal"] > [data-resize-handle] {
|
|
534
|
+
background-color: rgba(157, 124, 216, 0.18) !important;
|
|
535
|
+
transition: background-color 0.15s;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
.colorful [data-panel-group-direction="horizontal"] > [data-resize-handle]:hover {
|
|
539
|
+
background-color: rgba(157, 124, 216, 0.35) !important;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
.colorful [data-panel-group-direction="horizontal"] > [data-resize-handle][data-resize-handle-active] {
|
|
543
|
+
background-color: rgba(157, 124, 216, 0.50) !important;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/* ── Borders: single neutral tone everywhere ── */
|
|
547
|
+
.colorful .border-zinc-100,
|
|
548
|
+
.colorful .border-zinc-200,
|
|
549
|
+
.colorful .border-zinc-300,
|
|
550
|
+
.colorful .border-zinc-400,
|
|
551
|
+
.colorful .border-zinc-500,
|
|
552
|
+
.colorful .border-zinc-600,
|
|
553
|
+
.colorful .border-zinc-700,
|
|
554
|
+
.colorful .border-zinc-800,
|
|
555
|
+
.colorful .border-zinc-900,
|
|
556
|
+
.colorful .border-zinc-950 {
|
|
557
|
+
border-color: rgba(0, 0, 0, 0.10) !important;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
.colorful .border,
|
|
561
|
+
.colorful .border-b,
|
|
562
|
+
.colorful .border-t,
|
|
563
|
+
.colorful .border-l,
|
|
564
|
+
.colorful .border-r,
|
|
565
|
+
.colorful .border-border {
|
|
566
|
+
border-color: rgba(0, 0, 0, 0.10) !important;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/* Purple borders (property editor) stay purple but softened */
|
|
570
|
+
.colorful .border-purple-200,
|
|
571
|
+
.colorful .border-purple-300\/50,
|
|
572
|
+
.colorful .border-purple-500\/30,
|
|
573
|
+
.colorful .border-purple-700,
|
|
574
|
+
.colorful .border-purple-800 {
|
|
575
|
+
border-color: rgba(157, 124, 216, 0.25) !important;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/* ── Text ── */
|
|
579
|
+
.colorful .text-zinc-900,
|
|
580
|
+
.colorful .text-zinc-800,
|
|
581
|
+
.colorful .text-zinc-700,
|
|
582
|
+
.colorful .text-zinc-100 {
|
|
583
|
+
color: #1a1b2e !important;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
.colorful .text-zinc-500,
|
|
587
|
+
.colorful .text-zinc-400,
|
|
588
|
+
.colorful .text-zinc-600 {
|
|
589
|
+
color: #555b78 !important;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
.colorful .text-zinc-200,
|
|
593
|
+
.colorful .text-zinc-300 {
|
|
594
|
+
color: #40445e !important;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
/* ── Primary: purple (from Tokyo Night magenta/purple family) ── */
|
|
598
|
+
.colorful .bg-primary {
|
|
599
|
+
background-color: var(--cf-purple) !important;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
.colorful .text-primary {
|
|
603
|
+
color: var(--cf-purple) !important;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
.colorful .border-primary {
|
|
607
|
+
border-color: var(--cf-purple) !important;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
/* ── Shadows ── */
|
|
611
|
+
.colorful .shadow-lg,
|
|
612
|
+
.colorful .shadow-xl {
|
|
613
|
+
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08) !important;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/* ── Selection ── */
|
|
617
|
+
.colorful ::selection {
|
|
618
|
+
background-color: rgba(157, 124, 216, 0.25);
|
|
619
|
+
color: #1a1b2e;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/* ── Scrollbars ── */
|
|
623
|
+
.colorful .scrollbar-thin {
|
|
624
|
+
scrollbar-color: rgba(0, 0, 0, 0.15) transparent;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
.colorful .scrollbar-thin::-webkit-scrollbar-thumb {
|
|
628
|
+
background-color: rgba(0, 0, 0, 0.15);
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
.colorful .scrollbar-thin::-webkit-scrollbar-thumb:hover {
|
|
632
|
+
background-color: rgba(0, 0, 0, 0.25);
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
/* ── Hovers: tinted to match panel context ── */
|
|
636
|
+
.colorful .hover\:bg-primary:hover {
|
|
637
|
+
background-color: var(--cf-purple) !important;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
.colorful .hover\:bg-zinc-50:hover,
|
|
641
|
+
.colorful .hover\:bg-zinc-100:hover,
|
|
642
|
+
.colorful .hover\:bg-zinc-200:hover,
|
|
643
|
+
.colorful .hover\:bg-white:hover {
|
|
644
|
+
background-color: rgba(200, 195, 230, 0.18) !important;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
/* ── Active tabs ── */
|
|
648
|
+
.colorful [data-state="active"] {
|
|
649
|
+
background-color: var(--cf-glass-strong) !important;
|
|
650
|
+
color: #1a1b2e !important;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
.colorful .data-\[state\=active\]\:bg-white[data-state="active"],
|
|
654
|
+
.colorful .data-\[state\=active\]\:bg-zinc-100[data-state="active"] {
|
|
655
|
+
background-color: var(--cf-glass-strong) !important;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/* Properties tabs: warm orange accent on active (echoes aurora horizon) */
|
|
659
|
+
.colorful .properties-tab-trigger[data-state="active"] {
|
|
660
|
+
border-top-color: var(--cf-orange) !important;
|
|
661
|
+
background: rgba(245, 230, 210, 0.50) !important;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
/* ── Tabs container: warmer tint to match right panel ── */
|
|
665
|
+
.colorful .properties-tabs-list {
|
|
666
|
+
background-color: rgba(235, 215, 195, 0.30) !important;
|
|
667
|
+
border-bottom-color: rgba(0, 0, 0, 0.08) !important;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/* ── Tree selection: purple tint with left accent ── */
|
|
671
|
+
.colorful .tree-node.selected {
|
|
672
|
+
background-color: rgba(157, 124, 216, 0.12) !important;
|
|
673
|
+
border-left-color: var(--cf-purple) !important;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
.colorful .hierarchy-item.selected {
|
|
677
|
+
background-color: rgba(157, 124, 216, 0.12) !important;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
/* ── Hierarchy hover: subtle lavender ── */
|
|
681
|
+
.colorful .hierarchy-item:not(.selected):hover {
|
|
682
|
+
background-color: rgba(200, 195, 230, 0.20) !important;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
/* ── Quantity cards ── */
|
|
686
|
+
.colorful .border-blue-200,
|
|
687
|
+
.colorful .border-blue-800,
|
|
688
|
+
.colorful .border-blue-900 {
|
|
689
|
+
border-color: rgba(122, 162, 247, 0.25) !important;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
.colorful .text-blue-700,
|
|
693
|
+
.colorful .text-blue-400 {
|
|
694
|
+
color: #6a8fd6 !important;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
.colorful .bg-blue-50\/20,
|
|
698
|
+
.colorful .bg-blue-950\/20 {
|
|
699
|
+
background-color: rgba(122, 162, 247, 0.06) !important;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
/* ── Success / Location ── */
|
|
703
|
+
.colorful .border-emerald-500\/30 {
|
|
704
|
+
border-color: rgba(115, 218, 202, 0.25) !important;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
.colorful .text-emerald-800,
|
|
708
|
+
.colorful .text-emerald-400 {
|
|
709
|
+
color: #3d9e88 !important;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
.colorful .bg-emerald-50\/50,
|
|
713
|
+
.colorful .bg-emerald-900\/10 {
|
|
714
|
+
background-color: rgba(115, 218, 202, 0.06) !important;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
/* ── Toolbar buttons ── */
|
|
718
|
+
.colorful .toolbar-button:hover {
|
|
719
|
+
background-color: rgba(200, 195, 230, 0.25) !important;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
.colorful .toolbar-button.active {
|
|
723
|
+
background-color: var(--cf-purple) !important;
|
|
724
|
+
color: #fff !important;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
/* ── Status bar (bottom): warm tint ── */
|
|
728
|
+
.colorful .border-t.bg-white,
|
|
729
|
+
.colorful .border-t.dark\:bg-black {
|
|
730
|
+
background: rgba(240, 225, 210, 0.50) !important;
|
|
731
|
+
backdrop-filter: blur(16px) saturate(1.3) !important;
|
|
732
|
+
-webkit-backdrop-filter: blur(16px) saturate(1.3) !important;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
/* ── Drop overlay ── */
|
|
736
|
+
.colorful .bg-\[\#9ece6a\]\/10 {
|
|
737
|
+
background-color: rgba(115, 218, 202, 0.10) !important;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
.colorful .border-\[\#9ece6a\] {
|
|
741
|
+
border-color: var(--cf-teal) !important;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
.colorful .text-\[\#9ece6a\] {
|
|
745
|
+
color: var(--cf-teal) !important;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
/* ── Popover / dropdown menus: glass ── */
|
|
749
|
+
.colorful [data-radix-popper-content-wrapper] [role="menu"],
|
|
750
|
+
.colorful [data-radix-popper-content-wrapper] [role="listbox"],
|
|
751
|
+
.colorful [data-radix-popper-content-wrapper] [data-radix-collection-item] {
|
|
752
|
+
background: var(--cf-glass-strong) !important;
|
|
753
|
+
backdrop-filter: blur(20px) saturate(1.4) !important;
|
|
754
|
+
-webkit-backdrop-filter: blur(20px) saturate(1.4) !important;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
/* ═══════════════════════════════════════════════════════════════════════════
|
|
758
|
+
COLORFUL — Component-specific colour variations
|
|
759
|
+
Each section gets a subtle tint from the Tokyo palette, mapped to its
|
|
760
|
+
semantic role. Tasteful, not overwhelming.
|
|
761
|
+
═══════════════════════════════════════════════════════════════════════════ */
|
|
762
|
+
|
|
763
|
+
/* ── Section headers in hierarchy: cool lavender bg ── */
|
|
764
|
+
.colorful .bg-zinc-100.border-b,
|
|
765
|
+
.colorful .bg-zinc-900.border-b {
|
|
766
|
+
background-color: rgba(200, 195, 230, 0.30) !important;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
/* ── Section headers in properties: warm peach bg ── */
|
|
770
|
+
.colorful .bg-zinc-50.border-b {
|
|
771
|
+
background-color: rgba(240, 220, 195, 0.35) !important;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
/* Properties section header text: warmer dark tone */
|
|
775
|
+
.colorful .bg-zinc-50 .text-zinc-700,
|
|
776
|
+
.colorful .bg-zinc-50 .text-zinc-600 {
|
|
777
|
+
color: #5a4a3a !important;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
/* ── FILE INFORMATION / STATISTICS / PROJECT INFO section containers ── */
|
|
781
|
+
/* Alternate warm tints for each section in the properties panel */
|
|
782
|
+
.colorful .bg-zinc-50.dark\:bg-zinc-900\/50 {
|
|
783
|
+
background-color: rgba(240, 220, 195, 0.30) !important;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
/* ── LOCATION section: teal/green tint (geography = nature) ── */
|
|
787
|
+
.colorful [class*="border-emerald"] {
|
|
788
|
+
border-color: rgba(115, 218, 202, 0.25) !important;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
/* ── Landing page / empty state — orange-tinted grid world ── */
|
|
792
|
+
|
|
793
|
+
/* Viewport container bg — only the wrapper div, NOT the canvas.
|
|
794
|
+
The canvas has data-viewport="main"; we exclude it so the
|
|
795
|
+
inline aurora gradient isn't overridden by !important. */
|
|
796
|
+
.colorful div[data-viewport=""]:not(:has(canvas)),
|
|
797
|
+
.colorful div[data-viewport]:not([data-viewport="main"]) {
|
|
798
|
+
background-color: rgba(245, 235, 220, 0.60) !important;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
/* Orange grid only on the empty-state overlay (no model loaded).
|
|
802
|
+
This div only exists when the landing page renders. */
|
|
803
|
+
.colorful [data-viewport] > .absolute.z-10 {
|
|
804
|
+
background-image:
|
|
805
|
+
linear-gradient(rgba(255, 158, 100, 0.08) 1px, transparent 1px),
|
|
806
|
+
linear-gradient(90deg, rgba(255, 158, 100, 0.08) 1px, transparent 1px);
|
|
807
|
+
background-size: 32px 32px;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
/* Main landing card: warm glass with orange border */
|
|
811
|
+
.colorful .border-zinc-300.dark\:border-\[\#3b4261\] {
|
|
812
|
+
border-color: rgba(255, 158, 100, 0.28) !important;
|
|
813
|
+
background: rgba(255, 248, 240, 0.65) !important;
|
|
814
|
+
backdrop-filter: blur(16px) !important;
|
|
815
|
+
-webkit-backdrop-filter: blur(16px) !important;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
/* Logo background layer: warm tint */
|
|
819
|
+
.colorful .-rotate-3.border {
|
|
820
|
+
background-color: rgba(255, 225, 195, 0.30) !important;
|
|
821
|
+
border-color: rgba(255, 158, 100, 0.18) !important;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
/* Feature grid cards (SELECT / FILTER / ANALYZE): warm glass */
|
|
825
|
+
.colorful .bg-zinc-100.dark\:bg-\[\#1f2335\] {
|
|
826
|
+
background-color: rgba(255, 230, 200, 0.35) !important;
|
|
827
|
+
border-color: rgba(255, 158, 100, 0.20) !important;
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
/* Feature card icon boxes */
|
|
831
|
+
.colorful .bg-zinc-100 .bg-white.border,
|
|
832
|
+
.colorful .bg-zinc-100 .dark\:bg-\[\#16161e\].border {
|
|
833
|
+
background-color: rgba(255, 245, 230, 0.55) !important;
|
|
834
|
+
border-color: rgba(255, 158, 100, 0.15) !important;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
/* Recent files list */
|
|
838
|
+
.colorful .bg-zinc-50.dark\:bg-\[\#1f2335\] {
|
|
839
|
+
background-color: rgba(255, 235, 210, 0.30) !important;
|
|
840
|
+
border-color: rgba(255, 158, 100, 0.15) !important;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
/* Shortcuts badge */
|
|
844
|
+
.colorful .bg-zinc-100.dark\:bg-\[\#1f2335\].border.border-zinc-300 {
|
|
845
|
+
background-color: rgba(255, 230, 200, 0.35) !important;
|
|
846
|
+
border-color: rgba(255, 158, 100, 0.20) !important;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
/* "Open .ifc file" hover */
|
|
850
|
+
.colorful .hover\:border-primary:hover {
|
|
851
|
+
border-color: var(--cf-orange) !important;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
.colorful .hover\:text-primary:hover {
|
|
855
|
+
color: var(--cf-orange) !important;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
/* Empty state dashed borders: orange */
|
|
859
|
+
.colorful .border-dashed {
|
|
860
|
+
border-color: rgba(255, 158, 100, 0.35) !important;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
/* Empty state icon boxes (NO MODEL / NO SELECTION) */
|
|
864
|
+
.colorful .border-dashed.border-2 {
|
|
865
|
+
border-color: rgba(255, 158, 100, 0.30) !important;
|
|
866
|
+
background-color: rgba(255, 235, 210, 0.25) !important;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
/* ── Hierarchy SPATIAL/CLASS/TYPE toggle ── */
|
|
870
|
+
/* Outline buttons: lavender tint */
|
|
871
|
+
.colorful [data-variant="outline"] {
|
|
872
|
+
border-color: rgba(157, 124, 216, 0.22) !important;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
.colorful [data-variant="outline"]:hover {
|
|
876
|
+
background-color: rgba(200, 195, 230, 0.22) !important;
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
/* ── Properties panel collapsible sections hover (right panel only) ── */
|
|
880
|
+
.colorful [id="right-panel"] .hover\:bg-zinc-50:hover,
|
|
881
|
+
.colorful [id="right-panel"] .hover\:bg-zinc-900:hover {
|
|
882
|
+
background-color: rgba(240, 220, 195, 0.25) !important;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
/* ── Properties subsection backgrounds ── */
|
|
886
|
+
.colorful .bg-zinc-50\/50,
|
|
887
|
+
.colorful .dark\:bg-zinc-900\/50 {
|
|
888
|
+
background-color: rgba(240, 225, 205, 0.25) !important;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
/* ── Tooltip: dark, sharp ── */
|
|
892
|
+
.colorful [role="tooltip"] {
|
|
893
|
+
background: rgba(26, 27, 46, 0.90) !important;
|
|
894
|
+
color: #e0e6f0 !important;
|
|
895
|
+
backdrop-filter: blur(8px) !important;
|
|
896
|
+
-webkit-backdrop-filter: blur(8px) !important;
|
|
897
|
+
}
|
|
898
|
+
|
|
415
899
|
/* Fix Radix ScrollArea viewport inner div: by default it uses display:table
|
|
416
900
|
which expands to content width, preventing text truncation in flex children.
|
|
417
901
|
Force block layout so width constraints cascade correctly. */
|
|
@@ -528,13 +1012,3 @@ body {
|
|
|
528
1012
|
border-radius: 0.25rem;
|
|
529
1013
|
animation: skeleton-pulse 2s ease-in-out infinite;
|
|
530
1014
|
}
|
|
531
|
-
|
|
532
|
-
/* Clerk overlays (billing/sidebar/modal) should always stack above app overlays. */
|
|
533
|
-
.cl-portalRoot,
|
|
534
|
-
.cl-modalBackdrop,
|
|
535
|
-
.cl-modalContent,
|
|
536
|
-
.cl-drawerRoot,
|
|
537
|
-
.cl-drawerBackdrop,
|
|
538
|
-
.cl-drawerContent {
|
|
539
|
-
z-index: 100000 !important;
|
|
540
|
-
}
|
|
@@ -26,10 +26,8 @@ interface ResolvedDesktopEntitlement {
|
|
|
26
26
|
|
|
27
27
|
export function resolveDesktopEntitlement(options: ResolveDesktopEntitlementOptions): ResolvedDesktopEntitlement {
|
|
28
28
|
// NOTE: `token`, `has`, `publicMetadata`, and `now` are accepted but
|
|
29
|
-
// intentionally unused in this
|
|
30
|
-
//
|
|
31
|
-
// token validation, and time-based expiry via `now`) will be wired up once
|
|
32
|
-
// the Clerk integration is available in the desktop shell.
|
|
29
|
+
// intentionally unused in this implementation. They are kept for future
|
|
30
|
+
// extensibility if a desktop-specific entitlement provider is added.
|
|
33
31
|
const { userId } = options;
|
|
34
32
|
const entitlement: DesktopEntitlement = {
|
|
35
33
|
...getDefaultDesktopEntitlement(),
|
|
@@ -70,6 +70,7 @@ export async function createCesiumBridge(
|
|
|
70
70
|
mapConversion: MapConversion,
|
|
71
71
|
projectedCRS: ProjectedCRS,
|
|
72
72
|
coordinateInfo?: CoordinateInfo,
|
|
73
|
+
lengthUnitScale = 1,
|
|
73
74
|
): Promise<CesiumBridge | null> {
|
|
74
75
|
const projDef = await resolveProjection(projectedCRS);
|
|
75
76
|
if (!projDef) return null;
|
|
@@ -98,9 +99,13 @@ export async function createCesiumBridge(
|
|
|
98
99
|
const oIfcX = owx;
|
|
99
100
|
const oIfcY = -owz;
|
|
100
101
|
const oIfcZ = owy;
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
// Geometry coordinates (oIfcX/Y/Z) are already in metres (the geometry engine
|
|
103
|
+
// converts from the IFC file's native unit during extraction). MapConversion
|
|
104
|
+
// values use the unit from IfcProjectedCRS.MapUnit; fall back to project unit.
|
|
105
|
+
const mapScale = projectedCRS.mapUnitScale ?? lengthUnitScale;
|
|
106
|
+
const oEasting = mapConversion.eastings * mapScale + hScale * (absc * oIfcX - ordi * oIfcY);
|
|
107
|
+
const oNorthing = mapConversion.northings * mapScale + hScale * (ordi * oIfcX + absc * oIfcY);
|
|
108
|
+
const oHeight = mapConversion.orthogonalHeight * mapScale + oIfcZ;
|
|
104
109
|
|
|
105
110
|
let originLon: number, originLat: number;
|
|
106
111
|
try {
|
|
@@ -131,6 +136,8 @@ export async function createCesiumBridge(
|
|
|
131
136
|
// So M = [hScale*absc, 0, hScale*ordi ]
|
|
132
137
|
// [hScale*ordi, 0, -hScale*absc ]
|
|
133
138
|
// [0, 1, 0 ]
|
|
139
|
+
// Viewer-space deltas are already in metres (geometry engine converts during
|
|
140
|
+
// extraction), so no lengthUnitScale needed here.
|
|
134
141
|
const m00 = hScale * absc; // east from vx
|
|
135
142
|
const m01 = 0; // east from vy
|
|
136
143
|
const m02 = hScale * ordi; // east from vz
|
|
@@ -138,7 +145,7 @@ export async function createCesiumBridge(
|
|
|
138
145
|
const m11 = 0; // north from vy
|
|
139
146
|
const m12 = -hScale * absc; // north from vz
|
|
140
147
|
const m20 = 0; // up from vx
|
|
141
|
-
const m21 = 1; // up from vy
|
|
148
|
+
const m21 = 1; // up from vy (vertical = viewer Y, already metres)
|
|
142
149
|
const m22 = 0; // up from vz
|
|
143
150
|
|
|
144
151
|
// ── Cache for ECEF objects ──
|
|
@@ -288,9 +295,10 @@ export async function createCesiumBridge(
|
|
|
288
295
|
const ifcX = wx;
|
|
289
296
|
const ifcY = -wz;
|
|
290
297
|
const ifcZ = wy;
|
|
291
|
-
|
|
292
|
-
const
|
|
293
|
-
const
|
|
298
|
+
// Viewer coords (ifcX/Y/Z) are already in metres; only MapConversion values need scaling
|
|
299
|
+
const easting = mapConversion.eastings * mapScale + hScale * (absc * ifcX - ordi * ifcY);
|
|
300
|
+
const northing = mapConversion.northings * mapScale + hScale * (ordi * ifcX + absc * ifcY);
|
|
301
|
+
const height = mapConversion.orthogonalHeight * mapScale + ifcZ;
|
|
294
302
|
try {
|
|
295
303
|
const [lon, lat] = proj4(projDef!, 'WGS84', [easting, northing]);
|
|
296
304
|
if (!Number.isFinite(lat) || !Number.isFinite(lon)) return null;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
|
|
5
|
+
import { describe, it } from 'node:test';
|
|
6
|
+
import assert from 'node:assert';
|
|
7
|
+
|
|
8
|
+
import { inferMapUnitScale, mergeMapConversion, mergeProjectedCRS } from './effective-georef.js';
|
|
9
|
+
import type { MapConversion, ProjectedCRS } from '@ifc-lite/parser';
|
|
10
|
+
|
|
11
|
+
describe('effective georeferencing', () => {
|
|
12
|
+
it('recomputes map unit scale when the edited MapUnit changes', () => {
|
|
13
|
+
const original: ProjectedCRS = {
|
|
14
|
+
id: 1,
|
|
15
|
+
name: 'EPSG:28992',
|
|
16
|
+
mapUnit: 'METRE',
|
|
17
|
+
mapUnitScale: 1,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const merged = mergeProjectedCRS(original, { mapUnit: 'US SURVEY FOOT' }, 1);
|
|
21
|
+
|
|
22
|
+
assert.strictEqual(merged?.mapUnit, 'US SURVEY FOOT');
|
|
23
|
+
assert.strictEqual(merged?.mapUnitScale, 0.3048006096);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('preserves the extracted map unit scale when MapUnit was not edited', () => {
|
|
27
|
+
const original: ProjectedCRS = {
|
|
28
|
+
id: 1,
|
|
29
|
+
name: 'EPSG:1234',
|
|
30
|
+
mapUnit: 'CUSTOM',
|
|
31
|
+
mapUnitScale: 2.5,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const merged = mergeProjectedCRS(original, { description: 'Edited CRS' }, 1);
|
|
35
|
+
|
|
36
|
+
assert.strictEqual(merged?.description, 'Edited CRS');
|
|
37
|
+
assert.strictEqual(merged?.mapUnitScale, 2.5);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('overlays edited IfcMapConversion fields without dropping original rotation and scale', () => {
|
|
41
|
+
const original: MapConversion = {
|
|
42
|
+
id: 2,
|
|
43
|
+
sourceCRS: 10,
|
|
44
|
+
targetCRS: 11,
|
|
45
|
+
eastings: 100,
|
|
46
|
+
northings: 200,
|
|
47
|
+
orthogonalHeight: 5,
|
|
48
|
+
xAxisAbscissa: 0,
|
|
49
|
+
xAxisOrdinate: 1,
|
|
50
|
+
scale: 0.9999,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const merged = mergeMapConversion(original, { eastings: 150, orthogonalHeight: 9 });
|
|
54
|
+
|
|
55
|
+
assert.deepStrictEqual(merged, {
|
|
56
|
+
id: 2,
|
|
57
|
+
sourceCRS: 10,
|
|
58
|
+
targetCRS: 11,
|
|
59
|
+
eastings: 150,
|
|
60
|
+
northings: 200,
|
|
61
|
+
orthogonalHeight: 9,
|
|
62
|
+
xAxisAbscissa: 0,
|
|
63
|
+
xAxisOrdinate: 1,
|
|
64
|
+
scale: 0.9999,
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('infers common IFC map unit names', () => {
|
|
69
|
+
assert.strictEqual(inferMapUnitScale('FOOT'), 0.3048);
|
|
70
|
+
assert.strictEqual(inferMapUnitScale('METRE'), 1);
|
|
71
|
+
assert.strictEqual(inferMapUnitScale('MILLIMETRE'), 0.001);
|
|
72
|
+
});
|
|
73
|
+
});
|