fontastic 1.0.0 → 1.0.2
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/macos.yml +0 -7
- package/.github/workflows/ubuntu.yml +0 -7
- package/.github/workflows/windows.yml +0 -7
- package/README.md +1 -0
- package/app/core/ConnectionManager.js +7 -1
- package/app/core/ConnectionManager.ts +11 -3
- package/app/core/MessageHandler.js +24 -0
- package/app/core/MessageHandler.ts +29 -0
- package/app/core/menu/templates/DarwinTemplate.js +16 -1
- package/app/core/menu/templates/DarwinTemplate.ts +16 -1
- package/app/core/menu/templates/SystemTemplate.js +16 -1
- package/app/core/menu/templates/SystemTemplate.ts +16 -1
- package/app/database/entity/SmartCollection.schema.js +66 -0
- package/app/database/entity/SmartCollection.schema.ts +39 -0
- package/app/database/entity/index.js +1 -0
- package/app/database/entity/index.ts +2 -1
- package/app/database/repository/SmartCollection.repository.js +47 -0
- package/app/database/repository/SmartCollection.repository.ts +30 -0
- package/app/database/repository/Store.repository.js +107 -0
- package/app/database/repository/Store.repository.ts +106 -0
- package/app/database/repository/index.js +1 -0
- package/app/database/repository/index.ts +2 -1
- package/app/enums/ChannelType.js +5 -0
- package/app/enums/ChannelType.ts +6 -0
- package/app/enums/StorageType.js +1 -0
- package/app/enums/StorageType.ts +1 -0
- package/app/package.json +1 -1
- package/app/types/FontMetrics.js +3 -0
- package/app/types/SmartCollection.js +3 -0
- package/app/types/SmartCollection.ts +5 -0
- package/app/types/SystemConfig.ts +2 -1
- package/app/types/index.js +2 -0
- package/app/types/index.ts +1 -0
- package/package.json +1 -1
- package/src/app/core/services/database/database.service.ts +70 -1
- package/src/app/core/services/message/message.service.ts +23 -0
- package/src/app/core/services/presentation/presentation.service.ts +62 -9
- package/src/app/layout/header/header.component.html +5 -5
- package/src/app/layout/layout.component.html +1 -1
- package/src/app/layout/main/main.component.html +3 -3
- package/src/app/layout/main/main.component.ts +2 -2
- package/src/app/layout/navigation/navigation.component.html +70 -4
- package/src/app/layout/navigation/navigation.component.ts +131 -27
- package/src/app/shared/components/context-menu/context-menu.component.ts +70 -21
- package/src/app/shared/components/datagrid/datagrid.component.html +82 -2
- package/src/app/shared/components/{inspector/inspector.component.html → glyphs/glyphs.component.html} +1 -1
- package/src/app/shared/components/glyphs/glyphs.component.ts +60 -0
- package/src/app/shared/components/index.ts +2 -1
- package/src/app/shared/components/rule-builder/rule-builder.component.html +94 -0
- package/src/app/shared/components/rule-builder/rule-builder.component.ts +136 -0
- package/src/app/shared/components/toolbar/toolbar.component.html +0 -81
- package/src/app/shared/components/toolbar/toolbar.component.ts +1 -2
- package/src/styles/base/variables.css +16 -0
- package/src/styles/components/spinner.css +4 -3
- package/src/app/shared/components/inspector/inspector.component.ts +0 -41
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Brackets, Equal } from 'typeorm';
|
|
2
2
|
import { Store } from '../entity';
|
|
3
3
|
import { searchDbColumns } from '../../config';
|
|
4
|
+
import type { SmartCollectionRule } from '../../types';
|
|
4
5
|
|
|
5
6
|
export const StoreRepository = {
|
|
6
7
|
async search(options: any) {
|
|
@@ -330,6 +331,111 @@ export const StoreRepository = {
|
|
|
330
331
|
.catch((err: any) => console.log('insert-error', err));
|
|
331
332
|
},
|
|
332
333
|
|
|
334
|
+
async evaluateSmartRules(rules: SmartCollectionRule[], matchType: string, options: any = {}) {
|
|
335
|
+
const db = this.createQueryBuilder();
|
|
336
|
+
|
|
337
|
+
const textFields = [
|
|
338
|
+
'file_name',
|
|
339
|
+
'file_path',
|
|
340
|
+
'compatible_full_name',
|
|
341
|
+
'copyright',
|
|
342
|
+
'description',
|
|
343
|
+
'designer',
|
|
344
|
+
'designer_url',
|
|
345
|
+
'font_family',
|
|
346
|
+
'font_subfamily',
|
|
347
|
+
'full_name',
|
|
348
|
+
'license',
|
|
349
|
+
'license_url',
|
|
350
|
+
'manufacturer',
|
|
351
|
+
'manufacturer_url',
|
|
352
|
+
'post_script_name',
|
|
353
|
+
'preferred_family',
|
|
354
|
+
'preferred_sub_family',
|
|
355
|
+
'sample_text',
|
|
356
|
+
'trademark',
|
|
357
|
+
'unique_id',
|
|
358
|
+
'version',
|
|
359
|
+
];
|
|
360
|
+
const booleanFields = ['favorite', 'system', 'installable', 'temporary'];
|
|
361
|
+
const numericFields = ['file_size'];
|
|
362
|
+
const dateFields = ['created'];
|
|
363
|
+
|
|
364
|
+
if (rules.length > 0) {
|
|
365
|
+
const conditions: ((qb: any) => void)[] = rules.map((rule, idx) => {
|
|
366
|
+
const field = `store.${rule.field}`;
|
|
367
|
+
const paramName = `p${idx}`;
|
|
368
|
+
|
|
369
|
+
return (qb: any) => {
|
|
370
|
+
if (textFields.includes(rule.field)) {
|
|
371
|
+
const val = String(rule.value).toLowerCase();
|
|
372
|
+
switch (rule.operator) {
|
|
373
|
+
case 'contains':
|
|
374
|
+
qb.where(`LOWER(${field}) LIKE :${paramName}`, { [paramName]: `%${val}%` });
|
|
375
|
+
break;
|
|
376
|
+
case 'equals':
|
|
377
|
+
qb.where(`LOWER(${field}) = :${paramName}`, { [paramName]: val });
|
|
378
|
+
break;
|
|
379
|
+
case 'starts_with':
|
|
380
|
+
qb.where(`LOWER(${field}) LIKE :${paramName}`, { [paramName]: `${val}%` });
|
|
381
|
+
break;
|
|
382
|
+
case 'ends_with':
|
|
383
|
+
qb.where(`LOWER(${field}) LIKE :${paramName}`, { [paramName]: `%${val}` });
|
|
384
|
+
break;
|
|
385
|
+
default:
|
|
386
|
+
qb.where(`LOWER(${field}) LIKE :${paramName}`, { [paramName]: `%${val}%` });
|
|
387
|
+
}
|
|
388
|
+
} else if (rule.field === 'file_type') {
|
|
389
|
+
qb.where(`${field} = :${paramName}`, { [paramName]: rule.value });
|
|
390
|
+
} else if (booleanFields.includes(rule.field)) {
|
|
391
|
+
const boolVal = rule.operator === 'is_not' ? 0 : 1;
|
|
392
|
+
qb.where(`${field} = :${paramName}`, { [paramName]: boolVal });
|
|
393
|
+
} else if (numericFields.includes(rule.field)) {
|
|
394
|
+
if (rule.operator === 'greater_than') {
|
|
395
|
+
qb.where(`${field} > :${paramName}`, { [paramName]: rule.value });
|
|
396
|
+
} else if (rule.operator === 'less_than') {
|
|
397
|
+
qb.where(`${field} < :${paramName}`, { [paramName]: rule.value });
|
|
398
|
+
} else {
|
|
399
|
+
qb.where(`${field} = :${paramName}`, { [paramName]: rule.value });
|
|
400
|
+
}
|
|
401
|
+
} else if (dateFields.includes(rule.field)) {
|
|
402
|
+
if (rule.operator === 'greater_than') {
|
|
403
|
+
qb.where(`${field} >= :${paramName}`, { [paramName]: rule.value });
|
|
404
|
+
} else if (rule.operator === 'less_than') {
|
|
405
|
+
qb.where(`${field} <= :${paramName}`, { [paramName]: rule.value });
|
|
406
|
+
} else {
|
|
407
|
+
qb.where(`${field} = :${paramName}`, { [paramName]: rule.value });
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
const joiner = matchType === 'OR' ? 'orWhere' : 'andWhere';
|
|
414
|
+
conditions.forEach((condition, i) => {
|
|
415
|
+
if (i === 0) {
|
|
416
|
+
db.where(new Brackets(condition));
|
|
417
|
+
} else {
|
|
418
|
+
db[joiner](new Brackets(condition));
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
if (options.take) {
|
|
424
|
+
db.limit(options.take);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
if (options.skip) {
|
|
428
|
+
db.offset(options.skip);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if (options.order && options.order.column) {
|
|
432
|
+
const direction = options.order.direction === 'DESC' ? 'DESC' : 'ASC';
|
|
433
|
+
db.orderBy(`store.${options.order.column}`, direction);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
return await db.getManyAndCount();
|
|
437
|
+
},
|
|
438
|
+
|
|
333
439
|
async fetchSystemStats() {
|
|
334
440
|
const rowCount = await this.createQueryBuilder().select('COUNT(*)', 'total').getRawOne();
|
|
335
441
|
|
|
@@ -15,6 +15,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./Collection.repository"), exports);
|
|
18
|
+
__exportStar(require("./SmartCollection.repository"), exports);
|
|
18
19
|
__exportStar(require("./Store.repository"), exports);
|
|
19
20
|
__exportStar(require("./Logger.repository"), exports);
|
|
20
21
|
//# sourceMappingURL=index.js.map
|
package/app/enums/ChannelType.js
CHANGED
|
@@ -58,6 +58,11 @@ var ChannelType;
|
|
|
58
58
|
ChannelType["IPC_LOGGER_DELETE"] = "IPC_LOGGER_DELETE";
|
|
59
59
|
ChannelType["IPC_LOGGER_QUERY"] = "IPC_LOGGER_QUERY";
|
|
60
60
|
ChannelType["IPC_LOGGER_TRUNCATE"] = "IPC_LOGGER_TRUNCATE";
|
|
61
|
+
ChannelType["IPC_SMART_COLLECTION_FIND"] = "IPC_SMART_COLLECTION_FIND";
|
|
62
|
+
ChannelType["IPC_SMART_COLLECTION_CREATE"] = "IPC_SMART_COLLECTION_CREATE";
|
|
63
|
+
ChannelType["IPC_SMART_COLLECTION_UPDATE"] = "IPC_SMART_COLLECTION_UPDATE";
|
|
64
|
+
ChannelType["IPC_SMART_COLLECTION_DELETE"] = "IPC_SMART_COLLECTION_DELETE";
|
|
65
|
+
ChannelType["IPC_SMART_COLLECTION_EVALUATE"] = "IPC_SMART_COLLECTION_EVALUATE";
|
|
61
66
|
ChannelType["IPC_TOGGLE_PANEL"] = "IPC_TOGGLE_PANEL";
|
|
62
67
|
})(ChannelType || (exports.ChannelType = ChannelType = {}));
|
|
63
68
|
//# sourceMappingURL=ChannelType.js.map
|
package/app/enums/ChannelType.ts
CHANGED
|
@@ -63,5 +63,11 @@ export enum ChannelType {
|
|
|
63
63
|
IPC_LOGGER_QUERY = 'IPC_LOGGER_QUERY',
|
|
64
64
|
IPC_LOGGER_TRUNCATE = 'IPC_LOGGER_TRUNCATE',
|
|
65
65
|
|
|
66
|
+
IPC_SMART_COLLECTION_FIND = 'IPC_SMART_COLLECTION_FIND',
|
|
67
|
+
IPC_SMART_COLLECTION_CREATE = 'IPC_SMART_COLLECTION_CREATE',
|
|
68
|
+
IPC_SMART_COLLECTION_UPDATE = 'IPC_SMART_COLLECTION_UPDATE',
|
|
69
|
+
IPC_SMART_COLLECTION_DELETE = 'IPC_SMART_COLLECTION_DELETE',
|
|
70
|
+
IPC_SMART_COLLECTION_EVALUATE = 'IPC_SMART_COLLECTION_EVALUATE',
|
|
71
|
+
|
|
66
72
|
IPC_TOGGLE_PANEL = 'IPC_TOGGLE_PANEL',
|
|
67
73
|
}
|
package/app/enums/StorageType.js
CHANGED
|
@@ -16,5 +16,6 @@ var StorageType;
|
|
|
16
16
|
StorageType["LayoutPreview"] = "layout.preview";
|
|
17
17
|
StorageType["LayoutTheme"] = "layout.theme";
|
|
18
18
|
StorageType["AiKeys"] = "ai.keys";
|
|
19
|
+
StorageType["NavigationExpanded"] = "navigation.expanded";
|
|
19
20
|
})(StorageType || (exports.StorageType = StorageType = {}));
|
|
20
21
|
//# sourceMappingURL=StorageType.js.map
|
package/app/enums/StorageType.ts
CHANGED
package/app/package.json
CHANGED
|
@@ -30,7 +30,7 @@ export interface LayoutPanelType {
|
|
|
30
30
|
navigationEnabled: boolean;
|
|
31
31
|
toolbarEnabled: boolean;
|
|
32
32
|
previewEnabled: boolean;
|
|
33
|
-
|
|
33
|
+
glyphsEnabled: boolean;
|
|
34
34
|
searchEnabled: boolean;
|
|
35
35
|
waterfallEnabled: boolean;
|
|
36
36
|
}
|
|
@@ -46,6 +46,7 @@ export interface LayoutPreviewType {
|
|
|
46
46
|
displayText: string | null;
|
|
47
47
|
wordSpacing: number;
|
|
48
48
|
letterSpacing: number;
|
|
49
|
+
selectedGlyph: number | null;
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
export interface LayoutType {
|
package/app/types/index.js
CHANGED
|
@@ -15,6 +15,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./AppAlert"), exports);
|
|
18
|
+
__exportStar(require("./FontMetrics"), exports);
|
|
18
19
|
__exportStar(require("./AuthUser"), exports);
|
|
19
20
|
__exportStar(require("./Breadcrumb"), exports);
|
|
20
21
|
__exportStar(require("./QueryOptions"), exports);
|
|
@@ -22,4 +23,5 @@ __exportStar(require("./SystemTheme"), exports);
|
|
|
22
23
|
__exportStar(require("./SystemStats"), exports);
|
|
23
24
|
__exportStar(require("./SystemConfig"), exports);
|
|
24
25
|
__exportStar(require("./ImportOptions"), exports);
|
|
26
|
+
__exportStar(require("./SmartCollection"), exports);
|
|
25
27
|
//# sourceMappingURL=index.js.map
|
package/app/types/index.ts
CHANGED
package/package.json
CHANGED
|
@@ -7,6 +7,7 @@ import type { Collection } from '@main/database/entity/Collection.schema';
|
|
|
7
7
|
import type { Logger } from '@main/database/entity/Logger.schema';
|
|
8
8
|
import type { Store, StoreManyAndCountType } from '@main/database/entity/Store.schema';
|
|
9
9
|
import type { FontMetrics, SystemStats } from '@main/types';
|
|
10
|
+
import type { SmartCollection } from '@main/database/entity/SmartCollection.schema';
|
|
10
11
|
|
|
11
12
|
@Injectable({
|
|
12
13
|
providedIn: 'root',
|
|
@@ -18,6 +19,8 @@ export class DatabaseService {
|
|
|
18
19
|
|
|
19
20
|
// Reactive state
|
|
20
21
|
readonly collections = signal<Collection[]>([]);
|
|
22
|
+
readonly smartCollections = signal<SmartCollection[]>([]);
|
|
23
|
+
readonly activeSmartCollectionId = signal<number | null>(null);
|
|
21
24
|
readonly parentId = signal<number | null>(null);
|
|
22
25
|
readonly collectionId = signal<number | null>(null);
|
|
23
26
|
readonly stores = signal<Store[]>([]);
|
|
@@ -56,6 +59,7 @@ export class DatabaseService {
|
|
|
56
59
|
this.collectionId.set(parentId);
|
|
57
60
|
this.activeFilter.set(null);
|
|
58
61
|
this.activeSearchWhere.set(null);
|
|
62
|
+
this.activeSmartCollectionId.set(null);
|
|
59
63
|
this.currentPage.set(1);
|
|
60
64
|
}
|
|
61
65
|
|
|
@@ -64,6 +68,7 @@ export class DatabaseService {
|
|
|
64
68
|
this.collectionId.set(child.id);
|
|
65
69
|
this.activeFilter.set(null);
|
|
66
70
|
this.activeSearchWhere.set(null);
|
|
71
|
+
this.activeSmartCollectionId.set(null);
|
|
67
72
|
this.currentPage.set(1);
|
|
68
73
|
}
|
|
69
74
|
|
|
@@ -78,11 +83,22 @@ export class DatabaseService {
|
|
|
78
83
|
return current.id;
|
|
79
84
|
}
|
|
80
85
|
|
|
86
|
+
selectSmartCollection(id: number) {
|
|
87
|
+
this.parentId.set(null);
|
|
88
|
+
this.collectionId.set(null);
|
|
89
|
+
this.activeFilter.set(null);
|
|
90
|
+
this.activeSearchWhere.set(null);
|
|
91
|
+
this.activeSmartCollectionId.set(id);
|
|
92
|
+
this.currentPage.set(1);
|
|
93
|
+
this.fetchCurrentPage();
|
|
94
|
+
}
|
|
95
|
+
|
|
81
96
|
selectFilter(filter: string) {
|
|
82
97
|
this.parentId.set(null);
|
|
83
98
|
this.collectionId.set(null);
|
|
84
99
|
this.activeFilter.set(filter);
|
|
85
100
|
this.activeSearchWhere.set(null);
|
|
101
|
+
this.activeSmartCollectionId.set(null);
|
|
86
102
|
this.currentPage.set(1);
|
|
87
103
|
|
|
88
104
|
const whereMap: Record<string, { key: string; value: number }[]> = {
|
|
@@ -122,6 +138,12 @@ export class DatabaseService {
|
|
|
122
138
|
const skip = (this.currentPage() - 1) * this.pageSize();
|
|
123
139
|
const take = this.pageSize();
|
|
124
140
|
|
|
141
|
+
const smartCollectionId = this.activeSmartCollectionId();
|
|
142
|
+
if (smartCollectionId) {
|
|
143
|
+
this.smartCollectionEvaluate(smartCollectionId, { skip, take });
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
125
147
|
const searchWhere = this.activeSearchWhere();
|
|
126
148
|
if (searchWhere) {
|
|
127
149
|
const searchOrder = this.activeSearchOrder();
|
|
@@ -150,13 +172,15 @@ export class DatabaseService {
|
|
|
150
172
|
|
|
151
173
|
constructor() {
|
|
152
174
|
this.electron.ready.then(async () => {
|
|
153
|
-
const [collections, savedCollectionId, savedStoreId] = await Promise.all([
|
|
175
|
+
const [collections, smartCollections, savedCollectionId, savedStoreId] = await Promise.all([
|
|
154
176
|
this.message.collectionFetch({}),
|
|
177
|
+
this.message.smartCollectionFind(),
|
|
155
178
|
this.message.get(StorageType.CollectionId, null),
|
|
156
179
|
this.message.get(StorageType.StoreId, null),
|
|
157
180
|
]);
|
|
158
181
|
|
|
159
182
|
this.collections.set(collections);
|
|
183
|
+
this.smartCollections.set(smartCollections);
|
|
160
184
|
console.log('System Boot:', collections);
|
|
161
185
|
|
|
162
186
|
if (savedCollectionId) {
|
|
@@ -294,6 +318,50 @@ export class DatabaseService {
|
|
|
294
318
|
);
|
|
295
319
|
}
|
|
296
320
|
|
|
321
|
+
// Smart Collection
|
|
322
|
+
|
|
323
|
+
smartCollectionCreate(args: any): Promise<SmartCollection[]> {
|
|
324
|
+
return this.track(
|
|
325
|
+
this.message.smartCollectionCreate(args).then((result) => {
|
|
326
|
+
this.smartCollections.set(result);
|
|
327
|
+
return result;
|
|
328
|
+
}),
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
smartCollectionUpdate(id: number, data: any): Promise<SmartCollection[]> {
|
|
333
|
+
return this.track(
|
|
334
|
+
this.message.smartCollectionUpdate(id, data).then((result) => {
|
|
335
|
+
this.smartCollections.set(result);
|
|
336
|
+
return result;
|
|
337
|
+
}),
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
smartCollectionDelete(id: number): Promise<SmartCollection[]> {
|
|
342
|
+
return this.track(
|
|
343
|
+
this.message.smartCollectionDelete(id).then((result) => {
|
|
344
|
+
this.smartCollections.set(result);
|
|
345
|
+
if (this.activeSmartCollectionId() === id) {
|
|
346
|
+
this.activeSmartCollectionId.set(null);
|
|
347
|
+
this.stores.set([]);
|
|
348
|
+
this.storeCount.set(0);
|
|
349
|
+
}
|
|
350
|
+
return result;
|
|
351
|
+
}),
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
smartCollectionEvaluate(id: number, options: any): Promise<StoreManyAndCountType> {
|
|
356
|
+
return this.track(
|
|
357
|
+
this.message.smartCollectionEvaluate(id, options).then((result) => {
|
|
358
|
+
this.stores.set(result[0] as Store[]);
|
|
359
|
+
this.storeCount.set(result[1] as number);
|
|
360
|
+
return result;
|
|
361
|
+
}),
|
|
362
|
+
);
|
|
363
|
+
}
|
|
364
|
+
|
|
297
365
|
// Store
|
|
298
366
|
|
|
299
367
|
storeFind(args: any): Promise<Store[]> {
|
|
@@ -336,6 +404,7 @@ export class DatabaseService {
|
|
|
336
404
|
this.activeFilter.set(null);
|
|
337
405
|
this.activeSearchWhere.set(where);
|
|
338
406
|
this.activeSearchOrder.set(order ?? null);
|
|
407
|
+
this.activeSmartCollectionId.set(null);
|
|
339
408
|
this.currentPage.set(1);
|
|
340
409
|
this.fetchCurrentPage();
|
|
341
410
|
}
|
|
@@ -5,6 +5,7 @@ import type { Logger } from '@main/database/entity/Logger.schema';
|
|
|
5
5
|
import type { Store, StoreManyAndCountType } from '@main/database/entity/Store.schema';
|
|
6
6
|
import { ChannelType } from '@main/enums';
|
|
7
7
|
import type { FontMetrics, SystemConfig, SystemStats } from '@main/types';
|
|
8
|
+
import type { SmartCollection } from '@main/database/entity/SmartCollection.schema';
|
|
8
9
|
|
|
9
10
|
@Injectable({
|
|
10
11
|
providedIn: 'root',
|
|
@@ -213,6 +214,28 @@ export class MessageService {
|
|
|
213
214
|
return this.invoke<Collection[]>(ChannelType.IPC_COLLECTION_MOVE, { collectionId, newParentId, newIndex });
|
|
214
215
|
}
|
|
215
216
|
|
|
217
|
+
// Smart Collection
|
|
218
|
+
|
|
219
|
+
smartCollectionFind(): Promise<SmartCollection[]> {
|
|
220
|
+
return this.invoke<SmartCollection[]>(ChannelType.IPC_SMART_COLLECTION_FIND);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
smartCollectionCreate(args: any): Promise<SmartCollection[]> {
|
|
224
|
+
return this.invoke<SmartCollection[]>(ChannelType.IPC_SMART_COLLECTION_CREATE, args);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
smartCollectionUpdate(id: number, data: any): Promise<SmartCollection[]> {
|
|
228
|
+
return this.invoke<SmartCollection[]>(ChannelType.IPC_SMART_COLLECTION_UPDATE, { id, data });
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
smartCollectionDelete(id: number): Promise<SmartCollection[]> {
|
|
232
|
+
return this.invoke<SmartCollection[]>(ChannelType.IPC_SMART_COLLECTION_DELETE, { id });
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
smartCollectionEvaluate(id: number, options: any): Promise<StoreManyAndCountType> {
|
|
236
|
+
return this.invoke<StoreManyAndCountType>(ChannelType.IPC_SMART_COLLECTION_EVALUATE, { id, ...options });
|
|
237
|
+
}
|
|
238
|
+
|
|
216
239
|
// Store
|
|
217
240
|
|
|
218
241
|
storeFind(args: any): Promise<Store[]> {
|
|
@@ -41,6 +41,7 @@ export class PresentationService {
|
|
|
41
41
|
this.loadThemeSettings();
|
|
42
42
|
this.loadLayoutSettings();
|
|
43
43
|
this.loadPreviewSettings();
|
|
44
|
+
this.loadNavigationExpandedSettings();
|
|
44
45
|
this.listenForMenuToggle();
|
|
45
46
|
|
|
46
47
|
let themeInitialized = false;
|
|
@@ -60,7 +61,7 @@ export class PresentationService {
|
|
|
60
61
|
navigationEnabled: this.navigationEnabled(),
|
|
61
62
|
toolbarEnabled: this.toolbarEnabled(),
|
|
62
63
|
previewEnabled: this.previewEnabled(),
|
|
63
|
-
|
|
64
|
+
glyphsEnabled: this.glyphsEnabled(),
|
|
64
65
|
searchEnabled: this.searchEnabled(),
|
|
65
66
|
waterfallEnabled: this.waterfallEnabled(),
|
|
66
67
|
};
|
|
@@ -70,6 +71,15 @@ export class PresentationService {
|
|
|
70
71
|
panelInitialized = true;
|
|
71
72
|
});
|
|
72
73
|
|
|
74
|
+
let navExpandedInitialized = false;
|
|
75
|
+
effect(() => {
|
|
76
|
+
const ids = this.navigationExpandedIds();
|
|
77
|
+
if (navExpandedInitialized) {
|
|
78
|
+
untracked(() => this.messageService.set(StorageType.NavigationExpanded, ids));
|
|
79
|
+
}
|
|
80
|
+
navExpandedInitialized = true;
|
|
81
|
+
});
|
|
82
|
+
|
|
73
83
|
let previewInitialized = false;
|
|
74
84
|
effect(() => {
|
|
75
85
|
const settings: LayoutPreviewType = {
|
|
@@ -79,6 +89,7 @@ export class PresentationService {
|
|
|
79
89
|
displayText: this.customText(),
|
|
80
90
|
wordSpacing: this.wordSpacing(),
|
|
81
91
|
letterSpacing: this.letterSpacing(),
|
|
92
|
+
selectedGlyph: this.selectedGlyph(),
|
|
82
93
|
};
|
|
83
94
|
if (previewInitialized) {
|
|
84
95
|
untracked(() => this.messageService.set(StorageType.LayoutPreview, settings));
|
|
@@ -120,10 +131,14 @@ export class PresentationService {
|
|
|
120
131
|
readonly letterSpacing = signal(0);
|
|
121
132
|
readonly wordSpacing = signal(0);
|
|
122
133
|
|
|
134
|
+
readonly selectedGlyph = signal<number | null>(null);
|
|
135
|
+
|
|
136
|
+
readonly navigationExpandedIds = signal<number[]>([]);
|
|
137
|
+
|
|
123
138
|
readonly gridEnabled = signal(true);
|
|
124
139
|
readonly toolbarEnabled = signal(true);
|
|
125
140
|
readonly previewEnabled = signal(true);
|
|
126
|
-
readonly
|
|
141
|
+
readonly glyphsEnabled = signal(false);
|
|
127
142
|
readonly asideEnabled = signal(true);
|
|
128
143
|
readonly navigationEnabled = signal(true);
|
|
129
144
|
readonly searchEnabled = signal(false);
|
|
@@ -135,7 +150,7 @@ export class PresentationService {
|
|
|
135
150
|
this.gridEnabled(),
|
|
136
151
|
this.toolbarEnabled(),
|
|
137
152
|
this.previewEnabled(),
|
|
138
|
-
this.
|
|
153
|
+
this.glyphsEnabled(),
|
|
139
154
|
this.asideEnabled(),
|
|
140
155
|
this.navigationEnabled(),
|
|
141
156
|
].filter(Boolean).length,
|
|
@@ -150,8 +165,8 @@ export class PresentationService {
|
|
|
150
165
|
togglePreview() {
|
|
151
166
|
this.previewEnabled.update((v) => !v);
|
|
152
167
|
}
|
|
153
|
-
|
|
154
|
-
this.
|
|
168
|
+
toggleGlyphs() {
|
|
169
|
+
this.glyphsEnabled.update((v) => !v);
|
|
155
170
|
}
|
|
156
171
|
toggleAside() {
|
|
157
172
|
this.asideEnabled.update((v) => !v);
|
|
@@ -164,7 +179,7 @@ export class PresentationService {
|
|
|
164
179
|
this.searchEnabled.set(enabling);
|
|
165
180
|
if (enabling) {
|
|
166
181
|
this.waterfallEnabled.set(false);
|
|
167
|
-
this.
|
|
182
|
+
this.glyphsEnabled.set(false);
|
|
168
183
|
this.previewEnabled.set(false);
|
|
169
184
|
}
|
|
170
185
|
}
|
|
@@ -176,7 +191,7 @@ export class PresentationService {
|
|
|
176
191
|
navigation: () => this.toggleNavigation(),
|
|
177
192
|
aside: () => this.toggleAside(),
|
|
178
193
|
preview: () => this.togglePreview(),
|
|
179
|
-
|
|
194
|
+
glyphs: () => this.toggleGlyphs(),
|
|
180
195
|
toolbar: () => this.toggleToolbar(),
|
|
181
196
|
grid: () => this.toggleGrid(),
|
|
182
197
|
waterfall: () => this.toggleWaterfall(),
|
|
@@ -191,6 +206,41 @@ export class PresentationService {
|
|
|
191
206
|
});
|
|
192
207
|
}
|
|
193
208
|
|
|
209
|
+
isNavigationExpanded(id: number): boolean {
|
|
210
|
+
return this.navigationExpandedIds().includes(id);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
toggleNavigationExpanded(id: number) {
|
|
214
|
+
const ids = this.navigationExpandedIds();
|
|
215
|
+
if (ids.includes(id)) {
|
|
216
|
+
this.navigationExpandedIds.set(ids.filter((i) => i !== id));
|
|
217
|
+
} else {
|
|
218
|
+
this.navigationExpandedIds.set([...ids, id]);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
expandNavigationId(id: number) {
|
|
223
|
+
const ids = this.navigationExpandedIds();
|
|
224
|
+
if (!ids.includes(id)) {
|
|
225
|
+
this.navigationExpandedIds.set([...ids, id]);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
setAllNavigationExpanded(allIds: number[]) {
|
|
230
|
+
this.navigationExpandedIds.set(allIds);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
clearAllNavigationExpanded() {
|
|
234
|
+
this.navigationExpandedIds.set([]);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
private async loadNavigationExpandedSettings() {
|
|
238
|
+
const ids = (await this.messageService.get(StorageType.NavigationExpanded, null)) as number[] | null;
|
|
239
|
+
if (Array.isArray(ids)) {
|
|
240
|
+
this.navigationExpandedIds.set(ids);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
194
244
|
private async loadThemeSettings() {
|
|
195
245
|
const settings = (await this.messageService.get(StorageType.LayoutTheme, null)) as { theme: string } | null;
|
|
196
246
|
if (settings?.theme && PresentationService.themes.includes(settings.theme as (typeof PresentationService.themes)[number])) {
|
|
@@ -206,7 +256,7 @@ export class PresentationService {
|
|
|
206
256
|
this.navigationEnabled.set(settings.navigationEnabled);
|
|
207
257
|
this.toolbarEnabled.set(settings.toolbarEnabled);
|
|
208
258
|
this.previewEnabled.set(settings.previewEnabled);
|
|
209
|
-
this.
|
|
259
|
+
this.glyphsEnabled.set(settings.glyphsEnabled);
|
|
210
260
|
if (settings.searchEnabled !== undefined) {
|
|
211
261
|
this.searchEnabled.set(settings.searchEnabled);
|
|
212
262
|
}
|
|
@@ -227,6 +277,9 @@ export class PresentationService {
|
|
|
227
277
|
if (settings.displayText) {
|
|
228
278
|
this.customText.set(settings.displayText);
|
|
229
279
|
}
|
|
280
|
+
if (settings.selectedGlyph !== undefined) {
|
|
281
|
+
this.selectedGlyph.set(settings.selectedGlyph);
|
|
282
|
+
}
|
|
230
283
|
}
|
|
231
284
|
}
|
|
232
285
|
|
|
@@ -234,7 +287,7 @@ export class PresentationService {
|
|
|
234
287
|
this.gridEnabled.set(true);
|
|
235
288
|
this.toolbarEnabled.set(true);
|
|
236
289
|
this.previewEnabled.set(true);
|
|
237
|
-
this.
|
|
290
|
+
this.glyphsEnabled.set(false);
|
|
238
291
|
this.asideEnabled.set(true);
|
|
239
292
|
this.navigationEnabled.set(true);
|
|
240
293
|
this.searchEnabled.set(false);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<header class="grid
|
|
1
|
+
<header class="grid w-full h-full" [style.grid-template-columns]="'var(--panel-width) 1fr var(--panel-width)'">
|
|
2
2
|
<div class="relative">
|
|
3
3
|
<div class="p-0 h-full flex justify-items-start items-center">
|
|
4
4
|
<a
|
|
@@ -39,11 +39,11 @@
|
|
|
39
39
|
>
|
|
40
40
|
<a
|
|
41
41
|
href="javascript:;"
|
|
42
|
-
(click)="presentation.
|
|
42
|
+
(click)="presentation.toggleGlyphs()"
|
|
43
43
|
class="cursor-pointer text-[10px] font-medium tracking-wide text-center no-underline py-1 px-2 inline-flex flex-col items-center outline-none whitespace-nowrap transition-colors"
|
|
44
|
-
[style.color]="presentation.
|
|
45
|
-
title="Toggle
|
|
46
|
-
><i class="material-symbols-outlined block text-xl leading-none p-0 mb-0.5">info</i>
|
|
44
|
+
[style.color]="presentation.glyphsEnabled() ? 'var(--text-primary)' : 'var(--text-muted)'"
|
|
45
|
+
title="Toggle Glyphs"
|
|
46
|
+
><i class="material-symbols-outlined block text-xl leading-none p-0 mb-0.5">info</i> Glyphs</a
|
|
47
47
|
>
|
|
48
48
|
<a
|
|
49
49
|
href="javascript:;"
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<div
|
|
8
8
|
class="grid overflow-hidden"
|
|
9
9
|
[style.grid-template-columns]="
|
|
10
|
-
(presentation.navigationEnabled() ? '
|
|
10
|
+
(presentation.navigationEnabled() ? 'var(--panel-width) ' : '') + '1fr' + (presentation.asideEnabled() ? ' var(--panel-width)' : '')
|
|
11
11
|
"
|
|
12
12
|
>
|
|
13
13
|
@if (presentation.navigationEnabled()) {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[style.grid-template-rows]="
|
|
4
4
|
(presentation.searchEnabled() ? '1fr ' : '') +
|
|
5
5
|
(presentation.previewEnabled() ? '1fr ' : '') +
|
|
6
|
-
(presentation.
|
|
6
|
+
(presentation.glyphsEnabled() ? '1fr ' : '') +
|
|
7
7
|
(presentation.waterfallEnabled() ? '1fr ' : '') +
|
|
8
8
|
(presentation.toolbarEnabled() ? '42px ' : '') +
|
|
9
9
|
(presentation.gridEnabled() ? '1fr' : '')
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
<app-preview />
|
|
20
20
|
</app-panel>
|
|
21
21
|
}
|
|
22
|
-
@if (presentation.
|
|
22
|
+
@if (presentation.glyphsEnabled()) {
|
|
23
23
|
<app-panel class="overflow-auto" [style.border-bottom]="'1px solid var(--border-subtle)'">
|
|
24
|
-
<app-
|
|
24
|
+
<app-glyphs />
|
|
25
25
|
</app-panel>
|
|
26
26
|
}
|
|
27
27
|
@if (presentation.waterfallEnabled()) {
|
|
@@ -4,7 +4,7 @@ import { PanelComponent } from '../../shared/components/panel/panel.component';
|
|
|
4
4
|
import { PreviewComponent } from '../../shared/components/preview/preview.component';
|
|
5
5
|
import { DatagridComponent } from '../../shared/components/datagrid/datagrid.component';
|
|
6
6
|
import { ToolbarComponent } from '../../shared/components/toolbar/toolbar.component';
|
|
7
|
-
import {
|
|
7
|
+
import { GlyphsComponent } from '../../shared/components/glyphs/glyphs.component';
|
|
8
8
|
import { SearchComponent } from '../../shared/components/search/search.component';
|
|
9
9
|
import { WaterfallComponent } from '../../shared/components/waterfall/waterfall.component';
|
|
10
10
|
import { PresentationService } from '../../core/services';
|
|
@@ -12,7 +12,7 @@ import { PresentationService } from '../../core/services';
|
|
|
12
12
|
@Component({
|
|
13
13
|
selector: 'app-main',
|
|
14
14
|
standalone: true,
|
|
15
|
-
imports: [PanelComponent, PreviewComponent, DatagridComponent, ToolbarComponent,
|
|
15
|
+
imports: [PanelComponent, PreviewComponent, DatagridComponent, ToolbarComponent, GlyphsComponent, SearchComponent, WaterfallComponent],
|
|
16
16
|
templateUrl: './main.component.html',
|
|
17
17
|
})
|
|
18
18
|
export class MainComponent {
|