fontastic 1.3.1 → 1.4.0
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/.github/workflows/claude-code-review.yml +1 -1
- package/.github/workflows/claude.yml +1 -1
- package/.github/workflows/macos.yml +5 -5
- package/.github/workflows/release-please.yml +1 -1
- package/.github/workflows/release.yml +2 -2
- package/.github/workflows/ubuntu.yml +7 -7
- package/.github/workflows/windows.yml +5 -5
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +7 -0
- package/README.md +4 -4
- package/angular.json +8 -3
- package/app/core/FontFinder.js +17 -12
- package/app/core/FontFinder.ts +18 -12
- package/app/core/FontManager.js +13 -14
- package/app/core/FontManager.ts +12 -13
- package/app/core/MessageHandler.js +0 -1
- package/app/core/MessageHandler.ts +0 -4
- package/app/database/entity/Store.schema.js +1 -0
- package/app/database/entity/Store.schema.ts +1 -0
- package/app/database/repository/Collection.repository.js +0 -11
- package/app/database/repository/Collection.repository.ts +0 -22
- package/app/database/repository/Store.repository.js +50 -69
- package/app/database/repository/Store.repository.ts +47 -86
- package/app/enums/ChannelType.js +0 -1
- package/app/enums/ChannelType.ts +0 -1
- package/app/main.js +3 -2
- package/app/main.ts +3 -2
- package/app/package-lock.json +144 -1104
- package/app/package.json +4 -6
- package/app/preload.js +51 -0
- package/app/preload.ts +59 -0
- package/app/types/Bridge.js +3 -0
- package/app/types/Bridge.ts +19 -0
- package/app/types/index.js +1 -0
- package/app/types/index.ts +1 -0
- package/knip.json +18 -0
- package/package.json +44 -53
- package/src/app/app.component.spec.ts +3 -3
- package/src/app/app.component.ts +2 -15
- package/src/app/core/services/database/database.service.ts +8 -15
- package/src/app/core/services/electron/electron.service.ts +5 -46
- package/src/app/core/services/font-loader/font-loader.service.ts +60 -0
- package/src/app/core/services/index.ts +1 -0
- package/src/app/core/services/message/message.service.ts +19 -27
- package/src/app/core/services/presentation/presentation.service.ts +9 -2
- package/src/app/home/home.component.spec.ts +3 -3
- package/src/app/home/home.component.ts +4 -8
- package/src/app/layout/footer/footer.component.ts +6 -6
- package/src/app/shared/components/index.ts +0 -1
- package/src/app/shared/components/page-not-found/page-not-found.component.ts +2 -8
- package/src/app/shared/components/preview/preview.component.html +1 -0
- package/src/app/shared/components/preview/preview.component.ts +3 -31
- package/src/app/shared/components/rule-builder/rule-builder.component.html +4 -4
- package/src/app/shared/components/rule-builder/rule-builder.component.ts +13 -13
- package/src/app/shared/components/waterfall/waterfall.component.ts +1 -1
- package/src/app/shared/directives/index.ts +1 -1
- package/src/app/shared/directives/lazy-font/lazy-font.directive.ts +23 -0
- package/src/app/shared/shared.module.ts +3 -3
- package/src/main.ts +2 -2
- package/tsconfig.serve.json +4 -16
- package/app/helpers/command.js +0 -28
- package/app/helpers/command.ts +0 -20
- package/app/helpers/random.js +0 -16
- package/app/helpers/random.ts +0 -12
- package/src/app/shared/components/prompt-dialog/prompt-dialog.component.html +0 -36
- package/src/app/shared/components/prompt-dialog/prompt-dialog.component.ts +0 -40
- package/src/app/shared/directives/webview/webview.directive.spec.ts +0 -8
- package/src/app/shared/directives/webview/webview.directive.ts +0 -9
- package/src/styles/themes/dashboard.scss +0 -293
- package/src/styles/themes/euphoria.scss +0 -284
- package/src/styles/themes/mellow.scss +0 -281
- package/src/styles/themes/midnight.scss +0 -284
- package/src/styles/themes/passion.scss +0 -281
- package/src/styles/themes/swiss.scss +0 -284
|
@@ -317,7 +317,12 @@ export class PresentationService {
|
|
|
317
317
|
// --- Scan Progress (MessageChannelMain) ---
|
|
318
318
|
|
|
319
319
|
private initScanProgress() {
|
|
320
|
-
|
|
320
|
+
// The preload script forwards the MessagePort from the main process into
|
|
321
|
+
// the isolated world via window.postMessage (ports cannot cross the
|
|
322
|
+
// context bridge directly).
|
|
323
|
+
window.addEventListener('message', (event: MessageEvent) => {
|
|
324
|
+
if (event.source !== window || event.data?.type !== ChannelType.IPC_SCAN_PROGRESS_PORT) return;
|
|
325
|
+
|
|
321
326
|
const port = event.ports[0];
|
|
322
327
|
if (!port) return;
|
|
323
328
|
|
|
@@ -325,7 +330,9 @@ export class PresentationService {
|
|
|
325
330
|
this.scanProgress.set(msgEvent.data);
|
|
326
331
|
};
|
|
327
332
|
|
|
328
|
-
|
|
333
|
+
// `close` fires when the main process closes its end of the channel.
|
|
334
|
+
// (Not yet in the TS DOM lib, but supported since Chromium 126.)
|
|
335
|
+
(port as MessagePort & { onclose: (() => void) | null }).onclose = () => {
|
|
329
336
|
this.scanProgress.set(null);
|
|
330
337
|
};
|
|
331
338
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
2
|
|
|
3
3
|
import { HomeComponent } from './home.component';
|
|
4
|
-
import {
|
|
4
|
+
import { provideTranslateService } from '@ngx-translate/core';
|
|
5
5
|
import { provideRouter } from '@angular/router';
|
|
6
6
|
|
|
7
7
|
describe('HomeComponent', () => {
|
|
@@ -11,8 +11,8 @@ describe('HomeComponent', () => {
|
|
|
11
11
|
beforeEach(async () => {
|
|
12
12
|
await TestBed.configureTestingModule({
|
|
13
13
|
declarations: [],
|
|
14
|
-
imports: [HomeComponent
|
|
15
|
-
providers: [provideRouter([])],
|
|
14
|
+
imports: [HomeComponent],
|
|
15
|
+
providers: [provideRouter([]), provideTranslateService()],
|
|
16
16
|
}).compileComponents();
|
|
17
17
|
|
|
18
18
|
fixture = TestBed.createComponent(HomeComponent);
|
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
import { Component
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
2
|
import { RouterLink } from '@angular/router';
|
|
3
|
-
import {
|
|
3
|
+
import { TranslatePipe } from '@ngx-translate/core';
|
|
4
4
|
|
|
5
5
|
@Component({
|
|
6
6
|
selector: 'app-home',
|
|
7
7
|
templateUrl: './home.component.html',
|
|
8
8
|
standalone: true,
|
|
9
|
-
imports: [RouterLink,
|
|
9
|
+
imports: [RouterLink, TranslatePipe],
|
|
10
10
|
})
|
|
11
|
-
export class HomeComponent
|
|
12
|
-
ngOnInit(): void {
|
|
13
|
-
console.log('HomeComponent INIT');
|
|
14
|
-
}
|
|
15
|
-
}
|
|
11
|
+
export class HomeComponent {}
|
|
@@ -18,12 +18,12 @@ export class FooterComponent {
|
|
|
18
18
|
readonly nodeVersion = signal('');
|
|
19
19
|
|
|
20
20
|
constructor() {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
this.electronVersion.set(versions.electron
|
|
24
|
-
this.chromeVersion.set(versions.chrome
|
|
25
|
-
this.nodeVersion.set(versions.node
|
|
26
|
-
|
|
21
|
+
const bridge = this.electron.bridge;
|
|
22
|
+
if (bridge) {
|
|
23
|
+
this.electronVersion.set(bridge.versions.electron);
|
|
24
|
+
this.chromeVersion.set(bridge.versions.chrome);
|
|
25
|
+
this.nodeVersion.set(bridge.versions.node);
|
|
26
|
+
bridge.invoke<string>('app:get-version').then((v) => this.appVersion.set(v));
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
}
|
|
@@ -3,7 +3,6 @@ export * from './context-menu/context-menu.component';
|
|
|
3
3
|
export * from './page-not-found/page-not-found.component';
|
|
4
4
|
export * from './panel/panel.component';
|
|
5
5
|
export * from './datagrid/datagrid.component';
|
|
6
|
-
export * from './prompt-dialog/prompt-dialog.component';
|
|
7
6
|
export * from './rule-builder/rule-builder.component';
|
|
8
7
|
export * from './toolbar/toolbar.component';
|
|
9
8
|
export * from './glyphs/glyphs.component';
|
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
import { Component
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
2
|
|
|
3
3
|
@Component({
|
|
4
4
|
selector: 'app-page-not-found',
|
|
5
5
|
templateUrl: './page-not-found.component.html',
|
|
6
6
|
standalone: true,
|
|
7
7
|
})
|
|
8
|
-
export class PageNotFoundComponent
|
|
9
|
-
constructor() {}
|
|
10
|
-
|
|
11
|
-
ngOnInit(): void {
|
|
12
|
-
console.log('PageNotFoundComponent INIT');
|
|
13
|
-
}
|
|
14
|
-
}
|
|
8
|
+
export class PageNotFoundComponent {}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
class="pb-3 cursor-pointer transition-colors rounded-sm"
|
|
7
7
|
[style.border-color]="'var(--border-subtle)'"
|
|
8
8
|
[id]="'preview-store-' + store.id"
|
|
9
|
+
[appLazyFont]="store"
|
|
9
10
|
[style.background-color]="db.storeId() === store.id ? 'var(--selected-bg)' : 'transparent'"
|
|
10
11
|
(click)="selectStore(store.id)"
|
|
11
12
|
>
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { Component, inject
|
|
1
|
+
import { Component, inject } from '@angular/core';
|
|
2
2
|
import { DatabaseService, MessageService, PresentationService } from '../../../core/services';
|
|
3
3
|
import { ScrollResetDirective } from '../../directives/scroll-reset/scroll-reset.directive';
|
|
4
|
+
import { LazyFontDirective } from '../../directives/lazy-font/lazy-font.directive';
|
|
4
5
|
|
|
5
6
|
@Component({
|
|
6
7
|
selector: 'app-preview',
|
|
7
8
|
standalone: true,
|
|
8
|
-
imports: [ScrollResetDirective],
|
|
9
|
+
imports: [ScrollResetDirective, LazyFontDirective],
|
|
9
10
|
templateUrl: './preview.component.html',
|
|
10
11
|
})
|
|
11
12
|
export class PreviewComponent {
|
|
@@ -13,17 +14,6 @@ export class PreviewComponent {
|
|
|
13
14
|
readonly presentation = inject(PresentationService);
|
|
14
15
|
private messageService = inject(MessageService);
|
|
15
16
|
|
|
16
|
-
private registeredFonts = new Set<string>();
|
|
17
|
-
|
|
18
|
-
constructor() {
|
|
19
|
-
effect(() => {
|
|
20
|
-
const stores = this.db.stores();
|
|
21
|
-
if (stores) {
|
|
22
|
-
stores.forEach((store) => this.registerFont(store));
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
|
|
27
17
|
selectStore(id: number) {
|
|
28
18
|
this.db.storeId.set(id);
|
|
29
19
|
document.getElementById('grid-store-' + id)?.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
@@ -42,22 +32,4 @@ export class PreviewComponent {
|
|
|
42
32
|
this.messageService.openPath(store.file_path);
|
|
43
33
|
}
|
|
44
34
|
}
|
|
45
|
-
|
|
46
|
-
private registerFont(store: any) {
|
|
47
|
-
const key = `${store.id}-${store.file_path}`;
|
|
48
|
-
if (this.registeredFonts.has(key)) return;
|
|
49
|
-
|
|
50
|
-
const url = `font://${store.file_path}`;
|
|
51
|
-
const fontFace = new FontFace(store.full_name || store.font_family, `url('${url}')`);
|
|
52
|
-
|
|
53
|
-
fontFace
|
|
54
|
-
.load()
|
|
55
|
-
.then((loaded) => {
|
|
56
|
-
(document as any).fonts.add(loaded);
|
|
57
|
-
this.registeredFonts.add(key);
|
|
58
|
-
})
|
|
59
|
-
.catch((err) => {
|
|
60
|
-
console.warn(`Failed to load font: ${store.file_name}`, err);
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
35
|
}
|
|
@@ -84,12 +84,12 @@
|
|
|
84
84
|
Add Rule
|
|
85
85
|
</button>
|
|
86
86
|
<div class="flex items-center gap-2">
|
|
87
|
-
@if (previewCount !== null) {
|
|
88
|
-
<span class="text-xs opacity-70">{{ previewCount }} {{ previewCount === 1 ? 'font' : 'fonts' }} matched</span>
|
|
87
|
+
@if (previewCount() !== null) {
|
|
88
|
+
<span class="text-xs opacity-70">{{ previewCount() }} {{ previewCount() === 1 ? 'font' : 'fonts' }} matched</span>
|
|
89
89
|
}
|
|
90
|
-
<button class="btn btn-sm btn-default" (click)="preview()" [disabled]="previewing">
|
|
90
|
+
<button class="btn btn-sm btn-default" (click)="preview()" [disabled]="previewing()">
|
|
91
91
|
<span class="material-symbols-outlined" style="font-size: 16px; vertical-align: middle">search</span>
|
|
92
|
-
{{ previewing ? 'Checking...' : 'Preview' }}
|
|
92
|
+
{{ previewing() ? 'Checking...' : 'Preview' }}
|
|
93
93
|
</button>
|
|
94
94
|
</div>
|
|
95
95
|
</div>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Component, Input, Output, EventEmitter, OnInit, inject } from '@angular/core';
|
|
1
|
+
import { Component, Input, Output, EventEmitter, OnInit, inject, signal } from '@angular/core';
|
|
2
2
|
import { FormsModule } from '@angular/forms';
|
|
3
3
|
import { ModalBackdropDirective } from '../../directives/modal-backdrop/modal-backdrop.directive';
|
|
4
4
|
import { DatabaseService } from '../../../core/services/database/database.service';
|
|
@@ -81,8 +81,8 @@ export class RuleBuilderComponent implements OnInit {
|
|
|
81
81
|
title = '';
|
|
82
82
|
matchType: string = 'AND';
|
|
83
83
|
rules: SmartCollectionRule[] = [];
|
|
84
|
-
previewCount
|
|
85
|
-
previewing = false;
|
|
84
|
+
readonly previewCount = signal<number | null>(null);
|
|
85
|
+
readonly previewing = signal(false);
|
|
86
86
|
|
|
87
87
|
readonly fieldOptions = FIELD_OPTIONS;
|
|
88
88
|
|
|
@@ -121,32 +121,32 @@ export class RuleBuilderComponent implements OnInit {
|
|
|
121
121
|
} else {
|
|
122
122
|
rule.value = '';
|
|
123
123
|
}
|
|
124
|
-
this.previewCount
|
|
124
|
+
this.previewCount.set(null);
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
addRule(): void {
|
|
128
128
|
this.rules.push({ field: 'font_family', operator: 'contains', value: '' });
|
|
129
|
-
this.previewCount
|
|
129
|
+
this.previewCount.set(null);
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
removeRule(index: number): void {
|
|
133
133
|
this.rules.splice(index, 1);
|
|
134
|
-
this.previewCount
|
|
134
|
+
this.previewCount.set(null);
|
|
135
135
|
}
|
|
136
136
|
|
|
137
137
|
preview(): void {
|
|
138
|
-
if (this.rules.length === 0 || this.previewing) return;
|
|
139
|
-
this.previewing
|
|
140
|
-
this.previewCount
|
|
138
|
+
if (this.rules.length === 0 || this.previewing()) return;
|
|
139
|
+
this.previewing.set(true);
|
|
140
|
+
this.previewCount.set(null);
|
|
141
141
|
this.db
|
|
142
142
|
.smartCollectionPreview(this.rules, this.matchType)
|
|
143
143
|
.then((count) => {
|
|
144
|
-
this.previewCount
|
|
145
|
-
this.previewing
|
|
144
|
+
this.previewCount.set(count);
|
|
145
|
+
this.previewing.set(false);
|
|
146
146
|
})
|
|
147
147
|
.catch(() => {
|
|
148
|
-
this.previewCount
|
|
149
|
-
this.previewing
|
|
148
|
+
this.previewCount.set(null);
|
|
149
|
+
this.previewing.set(false);
|
|
150
150
|
});
|
|
151
151
|
}
|
|
152
152
|
|
|
@@ -72,7 +72,7 @@ export class WaterfallComponent {
|
|
|
72
72
|
|
|
73
73
|
private buildLowScale(ratio: number, baseMultiplier: number, length: number): ScaleItem[] {
|
|
74
74
|
let baseSize = 1;
|
|
75
|
-
let result
|
|
75
|
+
let result: number;
|
|
76
76
|
const items: ScaleItem[] = [];
|
|
77
77
|
|
|
78
78
|
for (let i = 0; i < length; i++) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export * from './autofocus/autofocus.directive';
|
|
2
2
|
export * from './disabled-opacity/disabled-opacity.directive';
|
|
3
3
|
export * from './hover-highlight/hover-highlight.directive';
|
|
4
|
+
export * from './lazy-font/lazy-font.directive';
|
|
4
5
|
export * from './modal-backdrop/modal-backdrop.directive';
|
|
5
6
|
export * from './scroll-reset/scroll-reset.directive';
|
|
6
7
|
export * from './stop-propagation/stop-propagation.directive';
|
|
7
|
-
export * from './webview/webview.directive';
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Directive, ElementRef, OnDestroy, OnInit, inject, input } from '@angular/core';
|
|
2
|
+
import { FontLoaderService } from '../../../core/services/font-loader/font-loader.service';
|
|
3
|
+
import type { Store } from '@main/database/entity/Store.schema';
|
|
4
|
+
|
|
5
|
+
/** Loads the given store's font file when the host element nears the viewport. */
|
|
6
|
+
@Directive({
|
|
7
|
+
selector: '[appLazyFont]',
|
|
8
|
+
standalone: true,
|
|
9
|
+
})
|
|
10
|
+
export class LazyFontDirective implements OnInit, OnDestroy {
|
|
11
|
+
private el = inject<ElementRef<HTMLElement>>(ElementRef);
|
|
12
|
+
private fontLoader = inject(FontLoaderService);
|
|
13
|
+
|
|
14
|
+
readonly appLazyFont = input.required<Store>();
|
|
15
|
+
|
|
16
|
+
ngOnInit() {
|
|
17
|
+
this.fontLoader.observe(this.el.nativeElement, this.appLazyFont());
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
ngOnDestroy() {
|
|
21
|
+
this.fontLoader.unobserve(this.el.nativeElement);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { NgModule } from '@angular/core';
|
|
2
2
|
import { CommonModule } from '@angular/common';
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { TranslatePipe } from '@ngx-translate/core';
|
|
5
5
|
|
|
6
6
|
import { FormsModule } from '@angular/forms';
|
|
7
7
|
|
|
8
8
|
@NgModule({
|
|
9
9
|
declarations: [],
|
|
10
|
-
imports: [CommonModule,
|
|
11
|
-
exports: [
|
|
10
|
+
imports: [CommonModule, TranslatePipe, FormsModule],
|
|
11
|
+
exports: [TranslatePipe, FormsModule],
|
|
12
12
|
})
|
|
13
13
|
export class SharedModule {}
|
package/src/main.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { enableProdMode,
|
|
1
|
+
import { enableProdMode, provideZonelessChangeDetection } from '@angular/core';
|
|
2
2
|
import { bootstrapApplication } from '@angular/platform-browser';
|
|
3
3
|
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
|
|
4
4
|
import { importProvidersFrom } from '@angular/core';
|
|
@@ -24,7 +24,7 @@ if (APP_CONFIG.production) {
|
|
|
24
24
|
|
|
25
25
|
bootstrapApplication(AppComponent, {
|
|
26
26
|
providers: [
|
|
27
|
-
|
|
27
|
+
provideZonelessChangeDetection(),
|
|
28
28
|
provideHttpClient(withInterceptorsFromDi()),
|
|
29
29
|
provideTranslateService({
|
|
30
30
|
loader: provideTranslateHttpLoader({
|
package/tsconfig.serve.json
CHANGED
|
@@ -7,21 +7,9 @@
|
|
|
7
7
|
"experimentalDecorators": true,
|
|
8
8
|
"module": "commonjs",
|
|
9
9
|
"target": "es2015",
|
|
10
|
-
"types": [
|
|
11
|
-
|
|
12
|
-
],
|
|
13
|
-
"lib": [
|
|
14
|
-
"es2017",
|
|
15
|
-
"es2016",
|
|
16
|
-
"es2015",
|
|
17
|
-
"dom"
|
|
18
|
-
]
|
|
10
|
+
"types": ["node"],
|
|
11
|
+
"lib": ["es2017", "es2016", "es2015", "dom"]
|
|
19
12
|
},
|
|
20
|
-
"files": [
|
|
21
|
-
|
|
22
|
-
],
|
|
23
|
-
"exclude": [
|
|
24
|
-
"node_modules",
|
|
25
|
-
"**/*.spec.ts"
|
|
26
|
-
]
|
|
13
|
+
"files": ["app/main.ts", "app/preload.ts"],
|
|
14
|
+
"exclude": ["node_modules", "**/*.spec.ts"]
|
|
27
15
|
}
|
package/app/helpers/command.js
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.prompt = exports.execute = void 0;
|
|
4
|
-
const child_process_1 = require("child_process");
|
|
5
|
-
const sudo = require('sudo-prompt');
|
|
6
|
-
const execute = (cmd, options = {}) => {
|
|
7
|
-
return new Promise((resolve, reject) => {
|
|
8
|
-
(0, child_process_1.exec)(cmd, options, (err, stdout, stderr) => {
|
|
9
|
-
if (err) {
|
|
10
|
-
return reject(err);
|
|
11
|
-
}
|
|
12
|
-
return resolve({ stdout, stderr });
|
|
13
|
-
});
|
|
14
|
-
});
|
|
15
|
-
};
|
|
16
|
-
exports.execute = execute;
|
|
17
|
-
const prompt = (cmd, options = {}) => {
|
|
18
|
-
return new Promise((resolve, reject) => {
|
|
19
|
-
sudo.exec(cmd, options, (err, stdout, stderr) => {
|
|
20
|
-
if (err) {
|
|
21
|
-
return reject(err);
|
|
22
|
-
}
|
|
23
|
-
return resolve({ stdout, stderr });
|
|
24
|
-
});
|
|
25
|
-
});
|
|
26
|
-
};
|
|
27
|
-
exports.prompt = prompt;
|
|
28
|
-
//# sourceMappingURL=command.js.map
|
package/app/helpers/command.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { exec } from 'child_process';
|
|
2
|
-
const sudo = require('sudo-prompt');
|
|
3
|
-
|
|
4
|
-
export const execute = (cmd: string, options = {}) => {
|
|
5
|
-
return new Promise((resolve, reject) => {
|
|
6
|
-
exec(cmd, options, (err: any, stdout: any, stderr: any) => {
|
|
7
|
-
if (err) { return reject(err); }
|
|
8
|
-
return resolve({ stdout, stderr });
|
|
9
|
-
});
|
|
10
|
-
});
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export const prompt = (cmd: string, options = {}) => {
|
|
14
|
-
return new Promise((resolve, reject) => {
|
|
15
|
-
sudo.exec(cmd, options, (err: any, stdout: any, stderr: any) => {
|
|
16
|
-
if (err) { return reject(err); }
|
|
17
|
-
return resolve({ stdout, stderr });
|
|
18
|
-
});
|
|
19
|
-
});
|
|
20
|
-
}
|
package/app/helpers/random.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.randNumber = void 0;
|
|
4
|
-
exports.randString = randString;
|
|
5
|
-
function randString(len = 7) {
|
|
6
|
-
const list = "ABCDEFGHIJKLMNPQRSTUVWXYZ123456789";
|
|
7
|
-
let res = "";
|
|
8
|
-
for (let i = 0; i < len; i++) {
|
|
9
|
-
let rnd = Math.floor(Math.random() * list.length);
|
|
10
|
-
res = res + list.charAt(rnd);
|
|
11
|
-
}
|
|
12
|
-
return res;
|
|
13
|
-
}
|
|
14
|
-
const randNumber = (n) => [...Array(n)].map(_ => Math.random() * 10 | 0).join('');
|
|
15
|
-
exports.randNumber = randNumber;
|
|
16
|
-
//# sourceMappingURL=random.js.map
|
package/app/helpers/random.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
export function randString(len: number = 7) {
|
|
3
|
-
const list = "ABCDEFGHIJKLMNPQRSTUVWXYZ123456789";
|
|
4
|
-
let res = "";
|
|
5
|
-
for (let i = 0; i < len; i++) {
|
|
6
|
-
let rnd = Math.floor(Math.random() * list.length);
|
|
7
|
-
res = res + list.charAt(rnd);
|
|
8
|
-
}
|
|
9
|
-
return res;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export const randNumber = (n: number) => [...Array(n)].map(_ => Math.random() * 10 | 0).join('');
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
<div class="fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm" appModalBackdrop (backdropClick)="cancel()">
|
|
2
|
-
<div class="card mb-0 w-[480px]" style="box-shadow: var(--context-shadow)">
|
|
3
|
-
<div class="card-header">
|
|
4
|
-
<div class="card-title">
|
|
5
|
-
<h3>{{ title }}</h3>
|
|
6
|
-
</div>
|
|
7
|
-
<div class="card-tools"></div>
|
|
8
|
-
</div>
|
|
9
|
-
<div class="card-body">
|
|
10
|
-
<div class="mb-4">
|
|
11
|
-
<label class="form-label" for="promptInput">Name</label>
|
|
12
|
-
<input
|
|
13
|
-
#promptInput
|
|
14
|
-
type="text"
|
|
15
|
-
class="form-input w-full"
|
|
16
|
-
id="promptInput"
|
|
17
|
-
[placeholder]="placeholder"
|
|
18
|
-
[(ngModel)]="value"
|
|
19
|
-
(keyup.enter)="confirm()"
|
|
20
|
-
(keyup.escape)="cancel()"
|
|
21
|
-
/>
|
|
22
|
-
</div>
|
|
23
|
-
</div>
|
|
24
|
-
<div class="card-footer">
|
|
25
|
-
<div></div>
|
|
26
|
-
<div class="card-tools">
|
|
27
|
-
<button class="btn btn-sm btn-default" (click)="cancel()">
|
|
28
|
-
{{ cancelText }}
|
|
29
|
-
</button>
|
|
30
|
-
<button class="btn btn-sm btn-theme" (click)="confirm()">
|
|
31
|
-
{{ confirmText }}
|
|
32
|
-
</button>
|
|
33
|
-
</div>
|
|
34
|
-
</div>
|
|
35
|
-
</div>
|
|
36
|
-
</div>
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { Component, Input, Output, EventEmitter, ElementRef, ViewChild, AfterViewInit } from '@angular/core';
|
|
2
|
-
import { FormsModule } from '@angular/forms';
|
|
3
|
-
import { ModalBackdropDirective } from '../../directives/modal-backdrop/modal-backdrop.directive';
|
|
4
|
-
|
|
5
|
-
@Component({
|
|
6
|
-
selector: 'app-prompt-dialog',
|
|
7
|
-
standalone: true,
|
|
8
|
-
imports: [FormsModule, ModalBackdropDirective],
|
|
9
|
-
templateUrl: './prompt-dialog.component.html',
|
|
10
|
-
})
|
|
11
|
-
export class PromptDialogComponent implements AfterViewInit {
|
|
12
|
-
@Input() title = 'Prompt';
|
|
13
|
-
@Input() placeholder = '';
|
|
14
|
-
@Input() confirmText = 'Confirm';
|
|
15
|
-
@Input() cancelText = 'Cancel';
|
|
16
|
-
|
|
17
|
-
@Output() confirmed = new EventEmitter<string>();
|
|
18
|
-
@Output() cancelled = new EventEmitter<void>();
|
|
19
|
-
|
|
20
|
-
@ViewChild('promptInput') promptInput!: ElementRef<HTMLInputElement>;
|
|
21
|
-
|
|
22
|
-
value = '';
|
|
23
|
-
|
|
24
|
-
ngAfterViewInit(): void {
|
|
25
|
-
this.promptInput.nativeElement.focus();
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
confirm(): void {
|
|
29
|
-
const trimmed = this.value.trim();
|
|
30
|
-
if (trimmed) {
|
|
31
|
-
this.confirmed.emit(trimmed);
|
|
32
|
-
this.value = '';
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
cancel(): void {
|
|
37
|
-
this.value = '';
|
|
38
|
-
this.cancelled.emit();
|
|
39
|
-
}
|
|
40
|
-
}
|