fontastic 1.0.2 → 1.1.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/README.md CHANGED
@@ -1,18 +1,19 @@
1
1
  # Fontastic
2
2
 
3
- ![Maintained][maintained-badge]
4
- [![Make a pull request][prs-badge]][prs]
5
- [![License][license-badge]](LICENSE.md)
3
+ [![Angular](https://img.shields.io/badge/Angular-21-dd0031?style=plastic&logo=angular&logoColor=white)](https://angular.dev)
4
+ [![Electron](https://img.shields.io/badge/Electron-40-47848f?style=plastic&logo=electron&logoColor=white)](https://electronjs.org)
5
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-3178c6?style=plastic&logo=typescript&logoColor=white)](https://www.typescriptlang.org)
6
+ [![License](https://img.shields.io/badge/License-MIT-f59e0b?style=plastic)](LICENSE.md)
7
+ [![PRs Welcome](https://img.shields.io/badge/PRs-Welcome-22c55e?style=plastic)](http://makeapullrequest.com)
6
8
 
7
9
  [![Linux Build][linux-build-badge]][linux-build]
8
10
  [![MacOS Build][macos-build-badge]][macos-build]
9
11
  [![Windows Build][windows-build-badge]][windows-build]
10
12
 
11
- [![Watch on GitHub][github-watch-badge]][github-watch]
12
- [![Star on GitHub][github-star-badge]][github-star]
13
- [![Tweet][twitter-badge]][twitter]
13
+ [![GitHub Stars](https://img.shields.io/github/stars/tomshaw/fontastic?style=plastic&logo=github&label=Stars)](https://github.com/tomshaw/fontastic/stargazers)
14
+ [![GitHub Watchers](https://img.shields.io/github/watchers/tomshaw/fontastic?style=plastic&logo=github&label=Watchers)](https://github.com/tomshaw/fontastic/watchers)
14
15
 
15
- Fontastic is a cross-platform font management and cataloging application built with Angular and Electron.
16
+ Fontastic is an Electron-based font management and cataloging application built for organizing, browsing, and inspecting font libraries.
16
17
 
17
18
  ## Features
18
19
 
@@ -83,12 +84,6 @@ Fontastic is open-sourced software licensed under the [MIT license](https://open
83
84
 
84
85
  [repo]: https://github.com/tomshaw/fontastic
85
86
 
86
- [maintained-badge]: https://img.shields.io/badge/maintained-yes-brightgreen
87
- [license-badge]: https://img.shields.io/badge/license-MIT-blue.svg
88
- [license]: https://github.com/tomshaw/fontastic/blob/main/LICENSE.md
89
- [prs-badge]: https://img.shields.io/badge/PRs-welcome-red.svg
90
- [prs]: http://makeapullrequest.com
91
-
92
87
  [linux-build-badge]: https://github.com/tomshaw/fontastic/workflows/Linux%20Build/badge.svg
93
88
  [linux-build]: https://github.com/tomshaw/fontastic/actions?query=workflow%3A%22Linux+Build%22
94
89
  [macos-build-badge]: https://github.com/tomshaw/fontastic/workflows/MacOS%20Build/badge.svg
@@ -96,9 +91,3 @@ Fontastic is open-sourced software licensed under the [MIT license](https://open
96
91
  [windows-build-badge]: https://github.com/tomshaw/fontastic/workflows/Windows%20Build/badge.svg
97
92
  [windows-build]: https://github.com/tomshaw/fontastic/actions?query=workflow%3A%22Windows+Build%22
98
93
 
99
- [github-watch-badge]: https://img.shields.io/github/watchers/tomshaw/fontastic.svg?style=social
100
- [github-watch]: https://github.com/tomshaw/fontastic/watchers
101
- [github-star-badge]: https://img.shields.io/github/stars/tomshaw/fontastic.svg?style=social
102
- [github-star]: https://github.com/tomshaw/fontastic/stargazers
103
- [twitter]: https://twitter.com/intent/tweet?text=Check%20out%20fontastic!%20https://github.com/tomshaw/fontastic%20%F0%9F%91%8D
104
- [twitter-badge]: https://img.shields.io/twitter/url/https/github.com/tomshaw/fontastic.svg?style=social
@@ -17,5 +17,7 @@ var StorageType;
17
17
  StorageType["LayoutTheme"] = "layout.theme";
18
18
  StorageType["AiKeys"] = "ai.keys";
19
19
  StorageType["NavigationExpanded"] = "navigation.expanded";
20
+ StorageType["SortColumn"] = "datagrid.sort.column";
21
+ StorageType["SortDirection"] = "datagrid.sort.direction";
20
22
  })(StorageType || (exports.StorageType = StorageType = {}));
21
23
  //# sourceMappingURL=StorageType.js.map
@@ -13,4 +13,6 @@ export enum StorageType {
13
13
  LayoutTheme = 'layout.theme',
14
14
  AiKeys = 'ai.keys',
15
15
  NavigationExpanded = 'navigation.expanded',
16
+ SortColumn = 'datagrid.sort.column',
17
+ SortDirection = 'datagrid.sort.direction',
16
18
  }
package/app/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "name": "Tom Shaw",
6
6
  "email": ""
7
7
  },
8
- "version": "1.0.2",
8
+ "version": "1.1.0",
9
9
  "main": "main.js",
10
10
  "private": true,
11
11
  "dependencies": {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "fontastic",
3
- "version": "1.0.2",
4
- "description": "A gorgeous multi-platform font management application.",
3
+ "version": "1.1.0",
4
+ "description": "Fontastic is an Electron-based font management and cataloging application built for organizing, browsing, and inspecting font libraries.",
5
5
  "homepage": "https://github.com/tomshaw/fontastic",
6
6
  "private": false,
7
7
  "author": {
@@ -137,24 +137,26 @@ export class DatabaseService {
137
137
  private fetchCurrentPage(extraOptions: any = {}) {
138
138
  const skip = (this.currentPage() - 1) * this.pageSize();
139
139
  const take = this.pageSize();
140
+ const sortOrder = this.getSortOrder();
140
141
 
141
142
  const smartCollectionId = this.activeSmartCollectionId();
142
143
  if (smartCollectionId) {
143
- this.smartCollectionEvaluate(smartCollectionId, { skip, take });
144
+ this.smartCollectionEvaluate(smartCollectionId, { skip, take, ...(sortOrder ? { order: sortOrder } : {}) });
144
145
  return;
145
146
  }
146
147
 
147
148
  const searchWhere = this.activeSearchWhere();
148
149
  if (searchWhere) {
149
150
  const searchOrder = this.activeSearchOrder();
150
- this.storeSearch({ where: searchWhere, skip, take, ...(searchOrder ? { order: searchOrder } : {}) });
151
+ const order = sortOrder ?? searchOrder;
152
+ this.storeSearch({ where: searchWhere, skip, take, ...(order ? { order } : {}) });
151
153
  return;
152
154
  }
153
155
 
154
156
  const collectionId = this.collectionId();
155
157
  const filter = this.activeFilter();
156
158
 
157
- const options: any = { skip, take, ...extraOptions };
159
+ const options: any = { skip, take, ...extraOptions, ...(sortOrder ? { order: sortOrder } : {}) };
158
160
 
159
161
  if (collectionId) {
160
162
  options.collectionId = collectionId;
@@ -172,17 +174,24 @@ export class DatabaseService {
172
174
 
173
175
  constructor() {
174
176
  this.electron.ready.then(async () => {
175
- const [collections, smartCollections, savedCollectionId, savedStoreId] = await Promise.all([
177
+ const [collections, smartCollections, savedCollectionId, savedStoreId, savedSortColumn, savedSortDirection] = await Promise.all([
176
178
  this.message.collectionFetch({}),
177
179
  this.message.smartCollectionFind(),
178
180
  this.message.get(StorageType.CollectionId, null),
179
181
  this.message.get(StorageType.StoreId, null),
182
+ this.message.get(StorageType.SortColumn, null),
183
+ this.message.get(StorageType.SortDirection, null),
180
184
  ]);
181
185
 
182
186
  this.collections.set(collections);
183
187
  this.smartCollections.set(smartCollections);
184
188
  console.log('System Boot:', collections);
185
189
 
190
+ if (savedSortColumn) {
191
+ this.sortColumn.set(savedSortColumn);
192
+ this.sortDirection.set(savedSortDirection === 'DESC' ? 'DESC' : 'ASC');
193
+ }
194
+
186
195
  if (savedCollectionId) {
187
196
  this.collectionId.set(savedCollectionId);
188
197
  }
@@ -398,6 +407,44 @@ export class DatabaseService {
398
407
 
399
408
  readonly activeSearchOrder = signal<{ column: string; direction: string } | null>(null);
400
409
 
410
+ // Datagrid sort (persisted)
411
+ readonly sortColumn = signal<string | null>(null);
412
+ readonly sortDirection = signal<'ASC' | 'DESC'>('ASC');
413
+
414
+ toggleSort(column: string) {
415
+ const current = this.sortColumn();
416
+ if (current === column) {
417
+ if (this.sortDirection() === 'ASC') {
418
+ this.sortDirection.set('DESC');
419
+ } else {
420
+ // Clear sort
421
+ this.sortColumn.set(null);
422
+ this.sortDirection.set('ASC');
423
+ }
424
+ } else {
425
+ this.sortColumn.set(column);
426
+ this.sortDirection.set('ASC');
427
+ }
428
+
429
+ // Persist
430
+ const col = this.sortColumn();
431
+ if (col) {
432
+ this.message.set(StorageType.SortColumn, col);
433
+ this.message.set(StorageType.SortDirection, this.sortDirection());
434
+ } else {
435
+ this.message.set(StorageType.SortColumn, null);
436
+ this.message.set(StorageType.SortDirection, null);
437
+ }
438
+
439
+ this.currentPage.set(1);
440
+ this.fetchCurrentPage();
441
+ }
442
+
443
+ private getSortOrder(): { column: string; direction: string } | null {
444
+ const col = this.sortColumn();
445
+ return col ? { column: col, direction: this.sortDirection() } : null;
446
+ }
447
+
401
448
  selectSearch(where: { key: string; value: any }[], order?: { column: string; direction: string }) {
402
449
  this.parentId.set(null);
403
450
  this.collectionId.set(null);
@@ -8,13 +8,31 @@
8
8
  >
9
9
  <tr class="text-left text-[11px] uppercase tracking-wide" [style.color]="'var(--text-muted)'">
10
10
  <th class="w-10 px-2 py-2 text-center font-medium"></th>
11
- <th class="px-4 py-2 font-medium">Name</th>
12
- <th class="px-4 py-2 font-medium">Family</th>
13
- <th class="px-4 py-2 font-medium">Style</th>
14
- <th class="px-4 py-2 font-medium">Type</th>
15
- <th class="px-4 py-2 font-medium">Size</th>
16
- <th class="px-4 py-2 font-medium">Version</th>
17
- <th class="px-4 py-2 font-medium">Designer</th>
11
+ @for (col of sortableColumns; track col.field) {
12
+ <th
13
+ class="px-4 py-2 font-medium cursor-pointer select-none transition-colors hover:brightness-125"
14
+ [class.max-w-48]="col.field === 'designer'"
15
+ (click)="db.toggleSort(col.field)"
16
+ >
17
+ <div class="flex items-center justify-between gap-1">
18
+ <span>{{ col.label }}</span>
19
+ @if (db.sortColumn() === col.field) {
20
+ <span
21
+ class="material-symbols-outlined"
22
+ style="
23
+ font-size: 14px;
24
+ font-variation-settings:
25
+ 'opsz' 20,
26
+ 'wght' 300;
27
+ "
28
+ [style.color]="'var(--accent)'"
29
+ >
30
+ {{ db.sortDirection() === 'ASC' ? 'arrow_upward' : 'arrow_downward' }}
31
+ </span>
32
+ }
33
+ </div>
34
+ </th>
35
+ }
18
36
  <th class="w-10 px-2 py-2 text-center font-medium"></th>
19
37
  <th class="w-10 px-2 py-2 text-center font-medium"></th>
20
38
  <th class="w-10 px-2 py-2 text-center font-medium"></th>
@@ -11,6 +11,16 @@ export class DatagridComponent {
11
11
  private messageService = inject(MessageService);
12
12
  private el = inject(ElementRef);
13
13
 
14
+ readonly sortableColumns = [
15
+ { field: 'full_name', label: 'Name' },
16
+ { field: 'font_family', label: 'Family' },
17
+ { field: 'font_subfamily', label: 'Style' },
18
+ { field: 'file_type', label: 'Type' },
19
+ { field: 'file_size', label: 'Size' },
20
+ { field: 'version', label: 'Version' },
21
+ { field: 'designer', label: 'Designer' },
22
+ ];
23
+
14
24
  constructor() {
15
25
  effect(() => {
16
26
  this.db.currentPage();