Added fuzzy search to the editor. Missing proper index handling of the plan display, I'd like to keep original indices on the filtered results

merge-notes
isark 2 years ago
parent c754789ffb
commit a81bcc908f

@ -20,7 +20,9 @@
"@angular/platform-browser": "^16.1.4",
"@angular/platform-browser-dynamic": "^16.1.4",
"@tauri-apps/api": "^1.2.0",
"@types/natural-compare": "^1.4.1",
"fuzzr": "github:isark2/fuzzr#v0.3.1",
"natural-compare": "^1.4.0",
"ngx-moveable": "^0.48.1",
"rxjs": "~7.8.1",
"tslib": "^2.6.0",

@ -93,9 +93,9 @@ fn main() {
app.manage(tx);
app.manage(Mutex::new(Storage::default()));
// app.get_window("Overlay")
// .expect("Could not get main overlay window")
// .open_devtools();
app.get_window("Overlay")
.expect("Could not get main overlay window")
.open_devtools();
Ok(())
})

@ -10,6 +10,7 @@ import { ConfigService } from "./services/config.service";
import { ColorPickerComponent } from './color-picker/color-picker.component';
import { MatButtonModule } from "@angular/material/button";
import { EditorComponent } from "./editor/editor.component";
import { initFuzzr } from "./fuzzr/fuzzr";
export function initializeApp(configService: ConfigService) {
return (): Promise<any> => {

@ -1,6 +1,7 @@
<div cdkDropListGroup *ngIf="areas" class="editor-container">
<div class="container">
<h2>available items</h2>
<div class="container">
<input type="text" [(ngModel)]="areaSearchString">
<h2>Campaign zones</h2>
<div
cdkDropList
@ -8,18 +9,24 @@
class="list areas"
cdkDropListSortingDisabled
(cdkDropListDropped)="dropHandler($event)">
<div class="box" *ngFor="let item of areas" cdkDrag>Name: {{item.name}}<br> in act {{item.act}}</div>
<div class="box" *ngFor="let item of filterAreas(areaSearchString)" cdkDrag>
Name: {{item.name}}<br> in act {{item.act}}
</div>
</div>
</div>
<div class="container">
<h2>Shopping basket</h2>
<input type="text" [(ngModel)]="planSearchString">
<h2>Plan</h2>
<div
cdkDropList
[cdkDropListData]="plan.plan"
class="list"
(cdkDropListDropped)="dropHandler($event)">
<div class="box" *ngFor="let item of plan.plan" cdkDrag>{{item.area_key}}</div>
<div class="box" *ngFor="let item of filterPlanElements(planSearchString); let index = index" cdkDrag>
<div class="area">{{areasMap?.get(item.area_key)?.name}}</div>
<div class="index">#{{index}}</div>
</div>
</div>
</div>
</div>

@ -1,68 +1,68 @@
:host {
height: 100%;
height: 100%;
}
.container {
width: 400px;
max-width: 100%;
margin: 0 25px 25px 0;
display: inline-block;
vertical-align: top;
flex-grow: 1 1 auto;
}
.list {
border: solid 1px #ccc;
min-height: 60px;
background: white;
border-radius: 4px;
display: block;
padding-bottom: 50px;
overflow: auto;
max-height: 100%;
}
.box {
padding: 20px 10px;
border-bottom: solid 1px #ccc;
color: rgba(0, 0, 0, 0.87);
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
cursor: move;
background: white;
font-size: 14px;
}
.cdk-drag-preview {
box-sizing: border-box;
border-radius: 4px;
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
0 8px 10px 1px rgba(0, 0, 0, 0.14),
0 3px 14px 2px rgba(0, 0, 0, 0.12);
}
.cdk-drag-placeholder {
opacity: 0;
}
.cdk-drag-animating {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}
.box:last-child {
border: none;
}
.list.cdk-drop-list-dragging .box:not(.cdk-drag-placeholder) {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}
width: 400px;
max-width: 100%;
margin: 0 25px 25px 0;
display: inline-block;
vertical-align: top;
flex-grow: 1 1 auto;
}
.list {
border: solid 1px #ccc;
min-height: 60px;
background: white;
border-radius: 4px;
display: block;
padding-bottom: 50px;
overflow: auto;
max-height: 100%;
}
.box {
padding: 10px 5px;
border-bottom: solid 1px #ccc;
color: rgba(0, 0, 0, 0.87);
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
cursor: move;
background: white;
font-size: 14px;
}
.cdk-drag-preview {
box-sizing: border-box;
border-radius: 4px;
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
0 8px 10px 1px rgba(0, 0, 0, 0.14),
0 3px 14px 2px rgba(0, 0, 0, 0.12);
}
.cdk-drag-placeholder {
opacity: 0;
}
.cdk-drag-animating {
transition: transform 75ms cubic-bezier(0, 0, 0.2, 1);
}
.box:last-child {
border: none;
}
.list.cdk-drop-list-dragging .box:not(.cdk-drag-placeholder) {
transition: transform 125ms cubic-bezier(0, 0, 0.2, 1);
}
.editor-container {
display: flex;
flex-direction: row;
height: 100%;
display: flex;
flex-direction: row;
height: 100%;
}

@ -1,4 +1,4 @@
import { Component, Input, OnInit } from '@angular/core';
import { Component, OnInit } from '@angular/core';
import {
CdkDrag,
@ -6,13 +6,14 @@ import {
CdkDropList,
CdkDropListGroup,
moveItemInArray,
transferArrayItem,
} from '@angular/cdk/drag-drop';
import { CommonModule } from '@angular/common';
import { WorldArea } from '../models/world-area';
import { Plan, PlanElement } from '../models/plan';
import { WorldAreaService } from '../services/world-area.service';
import { FormsModule } from '@angular/forms';
import { Fuzzr } from '../fuzzr/fuzzr';
@Component({
selector: 'plan-editor',
@ -21,6 +22,7 @@ import { WorldAreaService } from '../services/world-area.service';
standalone: true,
imports: [
CommonModule,
FormsModule,
CdkDropListGroup,
CdkDropList,
CdkDrag
@ -30,6 +32,10 @@ export class EditorComponent implements OnInit {
areas?: WorldArea[];
planAreas: WorldArea[];
plan: Plan;
areasMap?: Map<String, WorldArea>;
areaSearchString: string = "";
planSearchString: string = "";
planFuzzer: Fuzzr;
constructor(public worldAreaService: WorldAreaService) {
this.plan = {
@ -37,13 +43,19 @@ export class EditorComponent implements OnInit {
current: 0,
}
this.planFuzzer = new Fuzzr(this.plan.plan, {
toString: (e: PlanElement) => {
return this.areasMap?.get(e.area_key)?.name;
}
});
this.planAreas = [];
}
ngOnInit(): void {
this.worldAreaService.getWorldAreas().subscribe(worldAreas => {
this.areas = [...worldAreas.values()];
console.log(this.areas);
this.areasMap = worldAreas;
});
}
@ -62,4 +74,23 @@ export class EditorComponent implements OnInit {
notes: undefined,
};
}
filterAreas(searchString: string) {
if (searchString !== "") {
return this.worldAreaService.matcher?.search(searchString).map(({ item }) => {
return item[1];
});
} else {
return this.areas;
}
}
filterPlanElements(searchString: string) {
if (searchString !== "") {
return this.planFuzzer.search(searchString).map(({item}) => item);
} else {
return this.plan.plan;
}
}
}

@ -0,0 +1,8 @@
import init, { Fuzzr } from 'fuzzr/pkg';
export function initFuzzr() {
return init("/fuzzr/pkg/fuzzr_bg.wasm")
}
export { Fuzzr };

@ -8,4 +8,5 @@ export interface Plan {
export interface PlanElement {
area_key: string;
notes?: string;
index?: number;
}

@ -1,30 +1,27 @@
import { Injectable, NgZone } from '@angular/core';
import init, { Fuzzr } from 'fuzzr/pkg';
import { WorldArea } from '../models/world-area';
import { invoke } from '@tauri-apps/api';
import { Observable, ReplaySubject, Subject, filter, from, map } from 'rxjs';
import naturalCompare from 'natural-compare';
import { Fuzzr } from '../fuzzr/fuzzr';
@Injectable({
providedIn: 'root'
})
export class WorldAreaService {
private worldAreas?: Map<string, WorldArea>;
private matcher?: Fuzzr;
public matcher?: Fuzzr;
private worldAreasSubject = new ReplaySubject<Map<string, WorldArea>>();
private matcherSubject = new ReplaySubject<Fuzzr>();
constructor(private zone: NgZone) {
from(invoke<Map<string, WorldArea>>('load_world_areas')).subscribe((data) => {
this.worldAreas = new Map(Object.entries(data));
console.log("pre next worldareas");
const entries = Object.entries(data).sort((a, b) => naturalCompare(a[1].named_id, b[1].named_id));
this.worldAreas = new Map(entries);
this.zone.run(() => this.worldAreasSubject.next(this.worldAreas!));
console.log("post next worldareas");
from(init("/fuzzr/pkg/fuzzr_bg.wasm")).subscribe(() => {
this.matcher = new Fuzzr(this.worldAreas);
this.zone.run(() => this.matcherSubject.next(this.matcher!));
});
this.matcher = new Fuzzr(this.worldAreas, {
toString: (e: [string, WorldArea]) => e[1].name
})
});
}
@ -32,11 +29,5 @@ export class WorldAreaService {
return this.worldAreasSubject.asObservable().pipe(
filter(worldAreas => !!worldAreas),
);
}
getMatcher(): Observable<Fuzzr> {
return this.matcherSubject.asObservable().pipe(
filter(matcher => !!matcher),
);
}
}
}

@ -1,6 +1,10 @@
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
import { AppModule } from "./app/app.module";
import { initFuzzr } from "./app/fuzzr/fuzzr";
initFuzzr().then(() => {
platformBrowserDynamic()
.bootstrapModule(AppModule)
.catch((err) => console.error(err));
});
platformBrowserDynamic()
.bootstrapModule(AppModule)
.catch((err) => console.error(err));

@ -19,7 +19,8 @@
"target": "ES2022",
"module": "ES2022",
"useDefineForClassFields": false,
"lib": ["ES2022", "dom"]
"lib": ["ES2022", "dom"],
"esModuleInterop": true
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,

@ -2555,6 +2555,11 @@
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a"
integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==
"@types/natural-compare@^1.4.1":
version "1.4.1"
resolved "https://registry.yarnpkg.com/@types/natural-compare/-/natural-compare-1.4.1.tgz#fc2b11ea100d380b0de7af15768bef209157bfb9"
integrity sha512-9dr4UakpvN0QUvwNefk9+o14Sr1pPPIDWkgCxPkHcg3kyjtc9eKK1ng6dZ23vRwByloCqXYtZ1T5nJxkk3Ib3A==
"@types/node@*", "@types/node@>=10.0.0":
version "20.4.2"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.2.tgz#129cc9ae69f93824f92fac653eebfb4812ab4af9"
@ -5339,6 +5344,11 @@ nanoid@^3.3.6:
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c"
integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==
natural-compare@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
needle@^3.1.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/needle/-/needle-3.2.0.tgz#07d240ebcabfd65c76c03afae7f6defe6469df44"

Loading…
Cancel
Save