Revert "Keep a place, and come back to it"
This reverts commit bd3a5a4. The bookmarks work was committed onto this branch
by mistake — it belongs to its own pull request, and it has one, branched from
this branch's own tip. Reverting rather than rewinding because the branch is
published and a pull request is open against it: the diff this pull request
shows is what matters, and after this it shows the routing change alone.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { AfterViewInit, Component, ElementRef, OnDestroy, signal, viewChild } from '@angular/core';
|
||||
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
||||
import { ActivatedRoute, RouterLink } from '@angular/router';
|
||||
import { Subscription } from 'rxjs';
|
||||
import * as THREE from 'three/webgpu';
|
||||
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
|
||||
@@ -12,7 +12,6 @@ import { atmosphereColorFor, bodyTexturePath, loadCachedTexture, MILKY_WAY_SKYBO
|
||||
import { BodyRecord } from '../../shared/models/body.model';
|
||||
import { ExoplanetRecord } from '../../shared/models/exoplanet.model';
|
||||
import { StarRecord } from '../../shared/models/star.model';
|
||||
import { Bookmark } from '../../shared/state/bookmarks.store';
|
||||
import { NavigationStore } from '../../shared/state/navigation.store';
|
||||
import { ChevronIconComponent } from '../../shared/ui/chevron-icon.component';
|
||||
import { HudDockComponent } from '../hud/hud-dock.component';
|
||||
@@ -58,23 +57,12 @@ const GLOW_SCALE = 2.6;
|
||||
</a>
|
||||
</div>
|
||||
}
|
||||
<!-- Search and what has been kept: there is no scene readout here, the info panel is
|
||||
the reading, and the panel's own control is what keeps this body. -->
|
||||
<app-hud-dock (bookmarkChosen)="goToBookmark($event)" />
|
||||
<!-- Search only: there is no scene readout here, the info panel is the reading. -->
|
||||
<app-hud-dock />
|
||||
</div>
|
||||
`
|
||||
})
|
||||
export class BodyDetailSceneComponent implements AfterViewInit, OnDestroy {
|
||||
/** A kept place, revisited from this page: a star means leaving it for the map. */
|
||||
goToBookmark(bookmark: Bookmark): void {
|
||||
if (bookmark.kind === 'star') {
|
||||
this.navigationStore.selectStar(Number(bookmark.id));
|
||||
void this.router.navigate(['/']);
|
||||
} else {
|
||||
void this.router.navigate(['/body', String(bookmark.id)]);
|
||||
}
|
||||
}
|
||||
|
||||
private readonly canvasRef = viewChild.required<ElementRef<HTMLCanvasElement>>('canvas');
|
||||
|
||||
private controls?: OrbitControls;
|
||||
@@ -99,7 +87,6 @@ export class BodyDetailSceneComponent implements AfterViewInit, OnDestroy {
|
||||
private readonly engine: EngineService,
|
||||
private readonly dataLoader: DataLoaderService,
|
||||
private readonly route: ActivatedRoute,
|
||||
private readonly router: Router,
|
||||
private readonly navigationStore: NavigationStore
|
||||
) {}
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import { Component, computed, inject, input } from '@angular/core';
|
||||
import { Component, computed, input } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
import { BookmarksStore } from '../../shared/state/bookmarks.store';
|
||||
import { BookmarkIconComponent } from '../../shared/ui/bookmark-icon.component';
|
||||
import { ChevronIconComponent } from '../../shared/ui/chevron-icon.component';
|
||||
import { bodyReadouts } from './body-readouts';
|
||||
import { BodyDetailViewModel } from './body-detail.model';
|
||||
@@ -19,7 +17,7 @@ import { ReadoutSectionsComponent } from './readout-sections.component';
|
||||
*/
|
||||
@Component({
|
||||
selector: 'app-info-panel',
|
||||
imports: [BookmarkIconComponent, ChevronIconComponent, ReadoutSectionsComponent],
|
||||
imports: [ChevronIconComponent, ReadoutSectionsComponent],
|
||||
template: `
|
||||
<!-- Top-right, clear of the dock along the bottom; nothing else shares the top edge here. -->
|
||||
<div class="hud-brackets hud-acquire hud-surface absolute top-4 right-4 w-80 max-w-[calc(100%-2rem)] font-body text-text">
|
||||
@@ -32,21 +30,9 @@ import { ReadoutSectionsComponent } from './readout-sections.component';
|
||||
System
|
||||
</button>
|
||||
|
||||
<header class="flex items-start gap-2 px-4 pt-4 pb-3">
|
||||
<div class="min-w-0 flex-1">
|
||||
<h1 class="truncate text-lg leading-tight font-bold tracking-[0.04em] text-text uppercase">{{ body().name }}</h1>
|
||||
<p class="type-eyebrow mt-1 truncate text-accent">{{ readouts().kindLabel }} · {{ body().hostStarName }}</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
[attr.aria-label]="(bookmarks.has('body', body().id) ? 'Forget ' : 'Keep ') + body().name"
|
||||
[attr.aria-pressed]="bookmarks.has('body', body().id)"
|
||||
(click)="bookmarks.toggle({ kind: 'body', id: body().id, name: body().name })"
|
||||
class="shrink-0 p-1 transition-colors focus-visible:outline-1 focus-visible:-outline-offset-1 focus-visible:outline-accent"
|
||||
[class]="bookmarks.has('body', body().id) ? 'text-accent' : 'text-muted hover:text-accent'"
|
||||
>
|
||||
<app-bookmark-icon class="h-3.5 w-3.5" [kept]="bookmarks.has('body', body().id)" />
|
||||
</button>
|
||||
<header class="px-4 pt-4 pb-3">
|
||||
<h1 class="truncate text-lg leading-tight font-bold tracking-[0.04em] text-text uppercase">{{ body().name }}</h1>
|
||||
<p class="type-eyebrow mt-1 truncate text-accent">{{ readouts().kindLabel }} · {{ body().hostStarName }}</p>
|
||||
</header>
|
||||
|
||||
<app-readout-sections [readouts]="readouts()" />
|
||||
@@ -56,8 +42,6 @@ import { ReadoutSectionsComponent } from './readout-sections.component';
|
||||
export class InfoPanelComponent {
|
||||
readonly body = input.required<BodyDetailViewModel>();
|
||||
|
||||
readonly bookmarks = inject(BookmarksStore);
|
||||
|
||||
readonly readouts = computed(() => bodyReadouts(this.body()));
|
||||
|
||||
constructor(private readonly router: Router) {}
|
||||
|
||||
@@ -13,7 +13,6 @@ import { ExoplanetRecord } from '../../shared/models/exoplanet.model';
|
||||
import { applyMilkyWaySkybox, createGlowSprite } from '../../shared/rendering/skybox';
|
||||
import { loadCachedTexture, MILKY_WAY_SKYBOX_PATH, SUN_TEXTURE_PATH } from '../../shared/rendering/texture-catalog';
|
||||
import { StarRecord } from '../../shared/models/star.model';
|
||||
import { Bookmark } from '../../shared/state/bookmarks.store';
|
||||
import { NavigationStore, ViewLevel } from '../../shared/state/navigation.store';
|
||||
import { CameraRigController } from './camera-rig-controller';
|
||||
import { DeepSkyRenderer } from './deep-sky-renderer';
|
||||
@@ -226,14 +225,12 @@ function galacticOverviewPose(): { position: THREE.Vector3; target: THREE.Vector
|
||||
[routeResult]="routeResult()"
|
||||
[routeOptions]="routeOptions()"
|
||||
[currentStar]="currentStarOption()"
|
||||
[keepableStarId]="navigationStore.selectedStarId()"
|
||||
defaultTab="readout"
|
||||
(displayChange)="display.set($event)"
|
||||
(routeQuery)="onRouteQuery($event)"
|
||||
(routeRequested)="onRouteRequested($event)"
|
||||
(routeStarSelected)="navigationStore.selectStar($event)"
|
||||
(jumpRangeChange)="jumpRangePc.set($event)"
|
||||
(bookmarkChosen)="goToBookmark($event)"
|
||||
/>
|
||||
</div>
|
||||
`
|
||||
@@ -1207,15 +1204,6 @@ export class GalaxySystemSceneComponent implements AfterViewInit, OnDestroy {
|
||||
this.clearObjectCard();
|
||||
}
|
||||
|
||||
/** A kept place, revisited: a star is a system to fly into, a body is a page to open. */
|
||||
goToBookmark(bookmark: Bookmark): void {
|
||||
if (bookmark.kind === 'star') {
|
||||
this.navigationStore.selectStar(Number(bookmark.id));
|
||||
} else {
|
||||
this.openObjectDetail(String(bookmark.id));
|
||||
}
|
||||
}
|
||||
|
||||
/** The deliberate step out to the dedicated route, from the card's own control. */
|
||||
openObjectDetail(id: string): void {
|
||||
this.navigationStore.selectBody(id);
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { ChangeDetectionStrategy, Component, computed, inject, input, output } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, computed, input, output } from '@angular/core';
|
||||
|
||||
import { BodyDetailViewModel } from '../body-detail/body-detail.model';
|
||||
import { bodyReadouts } from '../body-detail/body-readouts';
|
||||
import { BookmarksStore } from '../../shared/state/bookmarks.store';
|
||||
import { BookmarkIconComponent } from '../../shared/ui/bookmark-icon.component';
|
||||
import { ReadoutSectionsComponent } from '../body-detail/readout-sections.component';
|
||||
import { ChevronIconComponent } from '../../shared/ui/chevron-icon.component';
|
||||
|
||||
@@ -21,7 +19,7 @@ import { ChevronIconComponent } from '../../shared/ui/chevron-icon.component';
|
||||
@Component({
|
||||
selector: 'app-system-object-card',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [BookmarkIconComponent, ChevronIconComponent, ReadoutSectionsComponent],
|
||||
imports: [ChevronIconComponent, ReadoutSectionsComponent],
|
||||
// Positioned and full-bleed like the HUD's own host, so the panel inside it resolves against
|
||||
// the scene rather than against whatever box the inline default would have left it in — which
|
||||
// put the card off the bottom-left corner of the viewport entirely.
|
||||
@@ -38,16 +36,6 @@ import { ChevronIconComponent } from '../../shared/ui/chevron-icon.component';
|
||||
<p class="truncate text-lg leading-tight font-bold tracking-[0.04em] text-text uppercase">{{ body().name }}</p>
|
||||
<p class="type-eyebrow mt-1 truncate text-accent">{{ readouts().kindLabel }} · {{ body().hostStarName }}</p>
|
||||
</header>
|
||||
<button
|
||||
type="button"
|
||||
[attr.aria-label]="(bookmarks.has('body', body().id) ? 'Forget ' : 'Keep ') + body().name"
|
||||
[attr.aria-pressed]="bookmarks.has('body', body().id)"
|
||||
(click)="bookmarks.toggle({ kind: 'body', id: body().id, name: body().name })"
|
||||
class="shrink-0 p-1 transition-colors focus-visible:outline-1 focus-visible:-outline-offset-1 focus-visible:outline-accent"
|
||||
[class]="bookmarks.has('body', body().id) ? 'text-accent' : 'text-muted hover:text-accent'"
|
||||
>
|
||||
<app-bookmark-icon class="h-3.5 w-3.5" [kept]="bookmarks.has('body', body().id)" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
(click)="dismissed.emit()"
|
||||
@@ -81,7 +69,5 @@ export class SystemObjectCardComponent {
|
||||
/** Request for the full `/body/:id` route. */
|
||||
readonly openRequested = output<void>();
|
||||
|
||||
readonly bookmarks = inject(BookmarksStore);
|
||||
|
||||
readonly readouts = computed(() => bodyReadouts(this.body()));
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import { Router } from '@angular/router';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { DataLoaderService } from '../../core/data/data-loader.service';
|
||||
import { BookmarksStore } from '../../shared/state/bookmarks.store';
|
||||
import { DEFAULT_HUD_DISPLAY, HudDisplay, HudDockComponent } from './hud-dock.component';
|
||||
|
||||
class EmptyDataLoaderService {
|
||||
@@ -47,7 +46,6 @@ describe('HudDockComponent', () => {
|
||||
}
|
||||
|
||||
beforeEach(async () => {
|
||||
localStorage.clear();
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [HudDockComponent],
|
||||
providers: [
|
||||
@@ -58,10 +56,9 @@ describe('HudDockComponent', () => {
|
||||
fixture = TestBed.createComponent(HudDockComponent);
|
||||
});
|
||||
|
||||
it('offers the search and what has been kept, when it has nothing else', () => {
|
||||
// Bookmarks are always offered: it is the only place that says the map can keep anything.
|
||||
it('offers only the search when it has nothing to read out and no layers', () => {
|
||||
fixture.detectChanges();
|
||||
expect(tabNames()).toEqual(['Search', 'Bookmarks']);
|
||||
expect(tabNames()).toEqual(['Search']);
|
||||
expect(host().querySelector('[role="tabpanel"]')).toBeNull();
|
||||
});
|
||||
|
||||
@@ -69,11 +66,11 @@ describe('HudDockComponent', () => {
|
||||
setReadout();
|
||||
fixture.componentRef.setInput('display', DEFAULT_HUD_DISPLAY);
|
||||
fixture.detectChanges();
|
||||
expect(tabNames()).toEqual(['Search', 'Readout', 'Bookmarks', 'Display']);
|
||||
expect(tabNames()).toEqual(['Search', 'Readout', 'Display']);
|
||||
|
||||
fixture.componentRef.setInput('routing', true);
|
||||
fixture.detectChanges();
|
||||
expect(tabNames()).toEqual(['Search', 'Readout', 'Routes', 'Bookmarks', 'Display']);
|
||||
expect(tabNames()).toEqual(['Search', 'Readout', 'Routes', 'Display']);
|
||||
});
|
||||
|
||||
it('opens the default tab on mount and renders the readout from its inputs', () => {
|
||||
@@ -144,80 +141,6 @@ describe('HudDockComponent', () => {
|
||||
expect(pressed).toEqual(['Labels=true', 'Orbits=true', 'Grid=false', 'Deep sky=true', 'Sky=true', 'Systems=true', 'Jump links=false']);
|
||||
});
|
||||
|
||||
it('says how to keep a place, rather than showing an empty list', () => {
|
||||
fixture.componentRef.setInput('defaultTab', 'bookmarks');
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(host().querySelector('#dock-panel-bookmarks ul')).toBeNull();
|
||||
expect(host().textContent).toContain('Nothing kept yet');
|
||||
});
|
||||
|
||||
it('lists what has been kept, newest first, and says which kind each is', () => {
|
||||
const bookmarks = TestBed.inject(BookmarksStore);
|
||||
bookmarks.toggle({ kind: 'star', id: 7, name: 'Sirius' });
|
||||
bookmarks.toggle({ kind: 'body', id: 'earth', name: 'Earth' });
|
||||
fixture.componentRef.setInput('defaultTab', 'bookmarks');
|
||||
fixture.detectChanges();
|
||||
|
||||
const rows = [...host().querySelectorAll('#dock-panel-bookmarks li')].map((li) => li.textContent?.replace(/\s+/g, ' ').trim());
|
||||
expect(rows[0]).toContain('Earth');
|
||||
expect(rows[0]).toContain('Body');
|
||||
expect(rows[1]).toContain('Sirius');
|
||||
expect(rows[1]).toContain('System');
|
||||
});
|
||||
|
||||
it('hands back the place that was chosen, whole', () => {
|
||||
const bookmarks = TestBed.inject(BookmarksStore);
|
||||
bookmarks.toggle({ kind: 'star', id: 7, name: 'Sirius' });
|
||||
fixture.componentRef.setInput('defaultTab', 'bookmarks');
|
||||
fixture.detectChanges();
|
||||
const chosen: unknown[] = [];
|
||||
fixture.componentInstance.bookmarkChosen.subscribe((bookmark) => chosen.push(bookmark));
|
||||
|
||||
host().querySelector<HTMLButtonElement>('#dock-panel-bookmarks li button')?.click();
|
||||
|
||||
expect(chosen).toEqual([{ kind: 'star', id: 7, name: 'Sirius' }]);
|
||||
});
|
||||
|
||||
it('forgets one without disturbing the rest', () => {
|
||||
const bookmarks = TestBed.inject(BookmarksStore);
|
||||
bookmarks.toggle({ kind: 'star', id: 7, name: 'Sirius' });
|
||||
bookmarks.toggle({ kind: 'body', id: 'earth', name: 'Earth' });
|
||||
fixture.componentRef.setInput('defaultTab', 'bookmarks');
|
||||
fixture.detectChanges();
|
||||
|
||||
host().querySelector<HTMLButtonElement>('[aria-label="Forget Earth"]')?.click();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(bookmarks.bookmarks().map((bookmark) => bookmark.name)).toEqual(['Sirius']);
|
||||
expect(host().textContent).not.toContain('Earth');
|
||||
});
|
||||
|
||||
it('keeps the star the readout is about, and says so on the control', () => {
|
||||
const bookmarks = TestBed.inject(BookmarksStore);
|
||||
setReadout();
|
||||
fixture.componentRef.setInput('title', 'Sirius');
|
||||
fixture.componentRef.setInput('keepableStarId', 7);
|
||||
fixture.componentRef.setInput('defaultTab', 'readout');
|
||||
fixture.detectChanges();
|
||||
|
||||
const keep = host().querySelector<HTMLButtonElement>('[aria-label="Keep Sirius"]');
|
||||
expect(keep?.getAttribute('aria-pressed')).toBe('false');
|
||||
keep?.click();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(bookmarks.has('star', 7)).toBe(true);
|
||||
expect(host().querySelector('[aria-label="Forget Sirius"]')?.getAttribute('aria-pressed')).toBe('true');
|
||||
});
|
||||
|
||||
it('offers nothing to keep where the readout is a scale rather than a place', () => {
|
||||
setReadout();
|
||||
fixture.componentRef.setInput('defaultTab', 'readout');
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(host().querySelector('[aria-label^="Keep"]')).toBeNull();
|
||||
});
|
||||
|
||||
it('opens the search on "/" from anywhere but a text field', () => {
|
||||
setReadout();
|
||||
fixture.componentRef.setInput('defaultTab', 'readout');
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { ChangeDetectionStrategy, Component, computed, ElementRef, HostListener, inject, input, OnInit, output, signal, viewChild } from '@angular/core';
|
||||
|
||||
import { Bookmark, BookmarksStore } from '../../shared/state/bookmarks.store';
|
||||
import { BookmarkIconComponent } from '../../shared/ui/bookmark-icon.component';
|
||||
import { SearchComponent } from '../search/search.component';
|
||||
import { RouteRequest, RouteResult, RoutesPanelComponent, RouteStarOption } from './routes-panel.component';
|
||||
|
||||
@@ -41,9 +39,9 @@ const DISPLAY_LAYERS: readonly { key: keyof HudDisplay; label: string }[] = [
|
||||
{ key: 'jumpLinks', label: 'Jump links' }
|
||||
];
|
||||
|
||||
export type DockTab = 'search' | 'readout' | 'routes' | 'bookmarks' | 'display';
|
||||
export type DockTab = 'search' | 'readout' | 'routes' | 'display';
|
||||
|
||||
const TAB_LABELS: Record<DockTab, string> = { search: 'Search', readout: 'Readout', routes: 'Routes', bookmarks: 'Bookmarks', display: 'Display' };
|
||||
const TAB_LABELS: Record<DockTab, string> = { search: 'Search', readout: 'Readout', routes: 'Routes', display: 'Display' };
|
||||
|
||||
/** Tailwind's `sm` breakpoint: below it the dock is a bare tab strip and its panel is a sheet. */
|
||||
const WIDE_VIEWPORT = '(min-width: 640px)';
|
||||
@@ -70,7 +68,7 @@ function isWideViewport(): boolean {
|
||||
@Component({
|
||||
selector: 'app-hud-dock',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [BookmarkIconComponent, RoutesPanelComponent, SearchComponent],
|
||||
imports: [RoutesPanelComponent, SearchComponent],
|
||||
host: { class: 'pointer-events-none fixed inset-x-2 bottom-2 z-20 block font-body sm:inset-x-6 sm:bottom-6' },
|
||||
template: `
|
||||
<!-- The column is transparent to the pointer and each surface in it opts back in: it is as
|
||||
@@ -89,21 +87,7 @@ function isWideViewport(): boolean {
|
||||
@case ('readout') {
|
||||
<section id="dock-panel-readout" role="tabpanel" aria-labelledby="dock-tab-readout" class="hud-acquire hud-brackets hud-surface pointer-events-auto mb-2 w-full max-w-lg px-4 py-3">
|
||||
<p class="type-label text-muted">{{ eyebrow() }}</p>
|
||||
<div class="mt-1 flex items-start gap-2">
|
||||
<p data-testid="hud-title" class="min-w-0 flex-1 text-lg font-bold tracking-[0.04em] text-text uppercase">{{ title() }}</p>
|
||||
@if (keepableStarId(); as starId) {
|
||||
<button
|
||||
type="button"
|
||||
[attr.aria-label]="(bookmarks.has('star', starId) ? 'Forget ' : 'Keep ') + title()"
|
||||
[attr.aria-pressed]="bookmarks.has('star', starId)"
|
||||
(click)="bookmarks.toggle({ kind: 'star', id: starId, name: title() })"
|
||||
class="shrink-0 p-1 transition-colors focus-visible:outline-1 focus-visible:-outline-offset-1 focus-visible:outline-accent"
|
||||
[class]="bookmarks.has('star', starId) ? 'text-accent' : 'text-muted hover:text-accent'"
|
||||
>
|
||||
<app-bookmark-icon class="h-3.5 w-3.5" [kept]="bookmarks.has('star', starId)" />
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
<p data-testid="hud-title" class="mt-1 text-lg font-bold tracking-[0.04em] text-text uppercase">{{ title() }}</p>
|
||||
@if (subtitle()) {
|
||||
<p class="mt-0.5 text-xs text-muted">{{ subtitle() }}</p>
|
||||
}
|
||||
@@ -135,40 +119,6 @@ function isWideViewport(): boolean {
|
||||
/>
|
||||
</section>
|
||||
}
|
||||
@case ('bookmarks') {
|
||||
<section id="dock-panel-bookmarks" role="tabpanel" aria-labelledby="dock-tab-bookmarks" class="hud-acquire hud-brackets hud-surface pointer-events-auto mb-2 w-full max-w-lg">
|
||||
@if (bookmarks.bookmarks().length) {
|
||||
<ul class="max-h-64 divide-y divide-border/25 overflow-y-auto">
|
||||
@for (bookmark of bookmarks.bookmarks(); track bookmark.kind + ':' + bookmark.id) {
|
||||
<li class="flex items-stretch">
|
||||
<button
|
||||
type="button"
|
||||
(click)="onBookmarkChosen(bookmark)"
|
||||
class="flex min-w-0 flex-1 items-baseline gap-3 px-3 py-2 text-left transition-colors hover:bg-accent/8 focus-visible:bg-accent/12 focus-visible:outline-1 focus-visible:-outline-offset-1 focus-visible:outline-accent"
|
||||
>
|
||||
<span class="min-w-0 flex-1 truncate text-sm text-text">{{ bookmark.name }}</span>
|
||||
<span class="type-label shrink-0 text-muted">{{ bookmark.kind === 'star' ? 'System' : 'Body' }}</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
[attr.aria-label]="'Forget ' + bookmark.name"
|
||||
(click)="bookmarks.remove(bookmark.kind, bookmark.id)"
|
||||
class="shrink-0 border-l border-border/25 px-3 text-muted transition-colors hover:bg-accent/8 hover:text-accent focus-visible:text-accent focus-visible:outline-1 focus-visible:-outline-offset-1 focus-visible:outline-accent"
|
||||
>
|
||||
<svg class="h-3 w-3" viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true">
|
||||
<path d="M3 3l8 8M11 3l-8 8" />
|
||||
</svg>
|
||||
</button>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
} @else {
|
||||
<p class="px-3 py-3 text-sm text-muted">
|
||||
Nothing kept yet. The <app-bookmark-icon class="inline-block h-3.5 w-3.5 -mb-0.5 text-accent" /> on a readout or a body keeps it here, in this browser.
|
||||
</p>
|
||||
}
|
||||
</section>
|
||||
}
|
||||
@case ('display') {
|
||||
<section id="dock-panel-display" role="tabpanel" aria-labelledby="dock-tab-display" class="hud-acquire hud-brackets hud-surface pointer-events-auto mb-2 w-full max-w-lg px-4 py-3">
|
||||
<p class="type-label text-muted">Layers</p>
|
||||
@@ -237,8 +187,6 @@ export class HudDockComponent implements OnInit {
|
||||
readonly routeResult = input<RouteResult | null>(null);
|
||||
readonly routeOptions = input<readonly RouteStarOption[]>([]);
|
||||
readonly currentStar = input<RouteStarOption | null>(null);
|
||||
/** The star the readout is about, where there is one to keep — a scale is not a place. */
|
||||
readonly keepableStarId = input<number | null>(null);
|
||||
/** Present makes the Routes tab available; absent means this surface cannot route. */
|
||||
readonly routing = input(false);
|
||||
|
||||
@@ -247,7 +195,6 @@ export class HudDockComponent implements OnInit {
|
||||
readonly routeRequested = output<RouteRequest>();
|
||||
readonly routeStarSelected = output<number>();
|
||||
readonly jumpRangeChange = output<number>();
|
||||
readonly bookmarkChosen = output<Bookmark>();
|
||||
|
||||
readonly layers = DISPLAY_LAYERS;
|
||||
readonly hasDerived = computed(() => this.readouts().some((readout) => readout.derived));
|
||||
@@ -255,16 +202,11 @@ export class HudDockComponent implements OnInit {
|
||||
'search',
|
||||
...(this.title() ? (['readout'] as const) : []),
|
||||
...(this.routing() ? (['routes'] as const) : []),
|
||||
// Always offered, even with nothing in it: it is the only place that says the map can keep
|
||||
// anything at all, and a tab that appears once you already know is a tab that never taught.
|
||||
'bookmarks',
|
||||
...(this.display() ? (['display'] as const) : [])
|
||||
]);
|
||||
|
||||
readonly activeTab = signal<DockTab | null>(null);
|
||||
|
||||
readonly bookmarks = inject(BookmarksStore);
|
||||
|
||||
private readonly search = viewChild(SearchComponent);
|
||||
private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);
|
||||
|
||||
@@ -296,13 +238,6 @@ export class HudDockComponent implements OnInit {
|
||||
this.routeStarSelected.emit(starId);
|
||||
}
|
||||
|
||||
/** Choosing a kept place is the same move as choosing a search result: the panel has done
|
||||
* its job and the thing to look at is now the scene. */
|
||||
onBookmarkChosen(bookmark: Bookmark): void {
|
||||
this.bookmarkChosen.emit(bookmark);
|
||||
this.onPicked();
|
||||
}
|
||||
|
||||
onPicked(): void {
|
||||
// A result was chosen: the thing to look at is now the scene, so hand the panel back to the
|
||||
// readout where there is one, and fold the sheet away where there is not. On a narrow
|
||||
|
||||
Reference in New Issue
Block a user