Skip to content

Commit d0981f1

Browse files
authored
Merge pull request #348 from CCDirectLink/347-load-maps-mod
moved "vanilla maps" checkbox to map loading
2 parents e03db74 + d616b65 commit d0981f1

12 files changed

Lines changed: 166 additions & 134 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
55

66
## [Unreleased]
7+
### Changed
8+
- Moved "vanilla maps" toggle from settings into the map loading dialog to allow quick switching between mod and vanilla maps [#347](https://github.com/CCDirectLink/crosscode-map-editor/issues/347)
9+
710
## [2.1.0] 2026-03-20
811
### Changed
912
- Changed scaling behaviour for json widget. Depending on content, it scales to 1-5 rows initially. When the user pastes multi-line json it also rescales to fit the content. [#344](https://github.com/CCDirectLink/crosscode-map-editor/issues/344)

backend/src/server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ app.use(bodyParser.urlencoded({ extended: true }));
2424
*/
2525
app.get('/api/allFiles', async (_, res) => res.json(await api.getAllFiles(config.pathToCrosscode)));
2626
app.get('/api/allTilesets', async (_, res) => res.json(await api.getAllTilesets(config.pathToCrosscode)));
27-
app.get('/api/allMaps', async (req, res) => res.json(await api.getAllMaps(config.pathToCrosscode, req.query['includeVanillaMaps'] == 'true')));
27+
app.get('/api/allMaps', async (req, res) => res.json(await api.getAllMaps(config.pathToCrosscode, req.query['vanillaMaps'] == 'true')));
2828
app.get('/api/allFilesInFolder', async (req, res) => res.json(await api.getAllFilesInFolder(config.pathToCrosscode, req.query['folder'] as string, req.query['extension'] as string)));
2929
app.get('/api/allMods', async (_, res) => res.json(await api.getAllMods(config.pathToCrosscode)));
3030
app.get('/api/allModMapEditorConfigs', async (_, res) => res.json(await api.getAllModMapEditorConfigs(config.pathToCrosscode)));

common/src/controllers/api.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -218,14 +218,13 @@ export async function getAllTilesets(dir: string) {
218218
return result.sort();
219219
}
220220

221-
export async function getAllMaps(dir: string, includeVanillaMaps: boolean) {
221+
export async function getAllMaps(dir: string, vanillaMaps: boolean) {
222222
const path = await pathPromise;
223223
const paths: string[] = [];
224224

225-
if (mods.length === 0 || includeVanillaMaps) {
225+
if (mods.length === 0 || vanillaMaps) {
226226
await listAllFiles(path.resolve(dir, 'data/maps/'), paths, 'json', path.resolve(dir));
227-
}
228-
if (mods.length > 0) {
227+
} else {
229228
const modDir = path.join(dir, 'mods', mods[0], 'assets');
230229
await listAllFiles(path.resolve(modDir, 'data/maps/'), paths, 'json', path.resolve(modDir));
231230
}

webapp/src/app/components/dialogs/load-map/load-map.component.html

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<button mat-icon-button (click)="fileUpload.click()">
99
<mat-icon>open_in_new</mat-icon>
1010
</button>
11-
<button mat-icon-button (click)="refresh()">
11+
<button mat-icon-button (click)="paths.reload()">
1212
<mat-icon>refresh</mat-icon>
1313
</button>
1414
<button mat-icon-button (click)="close()">
@@ -18,6 +18,18 @@
1818
</mat-toolbar>
1919

2020
<div class="filter no-error-msg flex flex-col">
21+
@if (currentMod) {
22+
<div class="mb-3">
23+
<mat-checkbox
24+
color="primary"
25+
[(ngModel)]="vanillaMaps"
26+
[disabled]="paths.isLoading()"
27+
>
28+
Vanilla Maps
29+
</mat-checkbox>
30+
</div>
31+
}
32+
2133
<mat-form-field
2234
appearance="outline"
2335
>
@@ -28,7 +40,7 @@
2840
<input #fileUpload type="file" class="hidden" (change)="loadMap($event)" accept=".json"/>
2941
</div>
3042
<div class="map-list">
31-
@if (!loading) {
43+
@if (!paths.isLoading()) {
3244
<mat-tree [dataSource]="mapsSource" [treeControl]="treeControl" class="mapTree">
3345
<mat-tree-node *matTreeNodeDef="let node">
3446
<li class="mat-tree-node">
@@ -37,11 +49,11 @@
3749
<mat-icon class="icon">edit</mat-icon>
3850
@for (name of node.names; track name; let isLast = $last) {
3951
<span>
40-
<a appHighlight [highlightText]="name" [highlightMatch]="filter"></a>
52+
<a appHighlight [highlightText]="name" [highlightMatch]="filter"></a>
4153
@if (!isLast) {
4254
<a class="separator">/</a>
4355
}
44-
</span>
56+
</span>
4557
}
4658
</button>
4759
</li>
@@ -55,11 +67,11 @@
5567
</mat-icon>
5668
@for (name of node.names; track name; let isLast = $last) {
5769
<span>
58-
<a appHighlight [highlightText]="name" [highlightMatch]="filter"></a>
70+
<a appHighlight [highlightText]="name" [highlightMatch]="filter"></a>
5971
@if (!isLast) {
6072
<a class="separator">/</a>
6173
}
62-
</span>
74+
</span>
6375
}
6476
</button>
6577
@if (treeControl.isExpanded(node)) {
@@ -71,12 +83,12 @@
7183
</mat-nested-tree-node>
7284
</mat-tree>
7385
} @else {
74-
75-
<div class="loader">
76-
<mat-spinner [diameter]="40" [strokeWidth]="5"></mat-spinner>
77-
</div>
78-
79-
}
86+
87+
<div class="loader">
88+
<mat-spinner [diameter]="40" [strokeWidth]="5"></mat-spinner>
89+
</div>
90+
91+
}
8092

8193
</div>
8294
</div>

webapp/src/app/components/dialogs/load-map/load-map.component.ts

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { NestedTreeControl } from '@angular/cdk/tree';
2-
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, inject, Input, ViewChild } from '@angular/core';
2+
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, effect, ElementRef, inject, Input, resource, untracked, ViewChild } from '@angular/core';
33
import { MatSidenav } from '@angular/material/sidenav';
44
import { MatNestedTreeNode, MatTree, MatTreeNestedDataSource, MatTreeNode, MatTreeNodeDef, MatTreeNodeOutlet, MatTreeNodeToggle } from '@angular/material/tree';
55

@@ -19,6 +19,9 @@ import { MatFormField, MatInput } from '@angular/material/input';
1919
import { FormsModule } from '@angular/forms';
2020
import { HighlightDirective } from '../../../directives/highlight.directive';
2121
import { MatProgressSpinner } from '@angular/material/progress-spinner';
22+
import { SHARED_SERVICE } from '../../../services/shared-service';
23+
import { MatCheckbox } from '@angular/material/checkbox';
24+
import { SettingsService } from '../../../services/settings.service';
2225

2326

2427
@Component({
@@ -41,8 +44,9 @@ import { MatProgressSpinner } from '@angular/material/progress-spinner';
4144
MatNestedTreeNode,
4245
MatTreeNodeToggle,
4346
MatTreeNodeOutlet,
44-
MatProgressSpinner
45-
]
47+
MatProgressSpinner,
48+
MatCheckbox,
49+
],
4650
})
4751
export class LoadMapComponent {
4852
private mapLoader = inject(MapLoaderService);
@@ -51,44 +55,57 @@ export class LoadMapComponent {
5155
private searchFilterService = inject(SearchFilterService);
5256
private readonly eventsService = inject(GlobalEventsService);
5357
private readonly overlayService = inject(OverlayService);
58+
private readonly sharedService = inject(SHARED_SERVICE);
59+
private readonly settingsService = inject(SettingsService);
5460

5561

56-
@ViewChild('fileUpload', {static: true})
62+
@ViewChild('fileUpload', { static: true })
5763
fileUpload!: ElementRef<HTMLInputElement>;
5864

59-
@ViewChild('filterInput', {static: true})
65+
@ViewChild('filterInput', { static: true })
6066
filterInput!: ElementRef<HTMLInputElement>;
6167

6268
@Input()
6369
sidenav!: MatSidenav;
6470

65-
loading = false;
71+
paths = resource({
72+
params: () => ({ vanillaMaps: this.vanillaMaps() }),
73+
loader: async ({ params }) => {
74+
const req = params.vanillaMaps ? this.http.getVanillaMaps() : this.http.getMaps();
75+
return await firstValueFrom(req);
76+
},
77+
});
6678

6779
treeControl = new NestedTreeControl<VirtualMapNode>(node => node.children);
6880
mapsSource = new MatTreeNestedDataSource<VirtualMapNode>();
6981

70-
root: MapNodeRoot = {name: '', displayed: true, children: []}; // The root itself is never displayed. It is used as a datasource for virtualRoot.
82+
root: MapNodeRoot = { name: '', displayed: true, children: [] }; // The root itself is never displayed. It is used as a datasource for virtualRoot.
7183
virtualRoot = new VirtualMapNode(this.root); // To reuse the children filtering.
7284
filter = '';
7385

86+
currentMod = '';
87+
vanillaMaps = this.settingsService.signalSettings().showVanillaMaps;
88+
7489
constructor() {
7590
this.mapsSource.data = [];
76-
this.refresh();
91+
this.currentMod = this.sharedService.getSelectedMod();
92+
93+
effect(() => {
94+
const paths = this.paths.value();
95+
if (!paths) {
96+
return;
97+
}
98+
untracked(() => {
99+
this.displayMaps(paths);
100+
this.update();
101+
});
102+
});
77103
}
78104

79105
focusInput() {
80106
this.filterInput.nativeElement.focus();
81107
}
82108

83-
refresh() {
84-
this.loading = true;
85-
this.http.getMaps().subscribe(paths => {
86-
this.loading = false;
87-
this.displayMaps(paths);
88-
this.update();
89-
});
90-
}
91-
92109
update() {
93110
for (const node of this.root.children) {
94111
this.filterNode(node, this.filter);
@@ -107,7 +124,7 @@ export class LoadMapComponent {
107124
const dialogRef = this.overlayService.open(ConfirmCloseComponent, {
108125
hasBackdrop: true,
109126
});
110-
const result = await firstValueFrom(dialogRef.ref.onClose, {defaultValue: false});
127+
const result = await firstValueFrom(dialogRef.ref.onClose, { defaultValue: false });
111128
if (result) {
112129
this.eventsService.hasUnsavedChanges.next(false);
113130
}
@@ -146,7 +163,7 @@ export class LoadMapComponent {
146163
const node = this.resolve(data, path, lastNode, lastPath);
147164
const name = path.substring(path.lastIndexOf('.') + 1);
148165

149-
node.push({name, path, displayed: true});
166+
node.push({ name, path, displayed: true });
150167

151168
lastPath = path;
152169
lastNode = node;

webapp/src/app/components/dialogs/settings/settings.component.html

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
<div fxLayout="row" class="option-row">
2727
<mat-form-field fxFlex="auto">
2828
<mat-label>Mod</mat-label>
29-
<mat-select [(value)]="mod" (selectionChange)="modSelectEvent($event.value)">
29+
<mat-select [(value)]="mod">
3030
<mat-option>None</mat-option>
3131
@for (mod of mods; track mod) {
3232
<mat-option [value]="mod.id"><span [appColoredText]="mod.displayName"></span></mat-option>
@@ -35,15 +35,6 @@
3535
<mat-hint>Maps will be stored and loaded from the selected mod</mat-hint>
3636
</mat-form-field>
3737
</div>
38-
<div fxLayout="row" class="option-row">
39-
<mat-checkbox
40-
[(ngModel)]="settings.includeVanillaMaps"
41-
color="primary"
42-
[disabled]="isIncludeVanillaMapsDisabled"
43-
>
44-
Include vanilla maps
45-
</mat-checkbox>
46-
</div>
4738
<div fxLayout="row" class="option-row">
4839
<mat-checkbox
4940
[(ngModel)]="settings.wrapEventEditorLines"

0 commit comments

Comments
 (0)