fontastic 0.1.3 → 0.2.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.
Files changed (452) hide show
  1. package/.editorconfig +16 -16
  2. package/.github/FUNDING.yml +3 -12
  3. package/.github/ISSUE_TEMPLATE/bug_report.yml +41 -0
  4. package/.github/ISSUE_TEMPLATE/feature_request.yml +29 -0
  5. package/.github/dependabot.yml +6 -6
  6. package/.github/pull_request_template.md +21 -21
  7. package/.github/workflows/claude-code-review.yml +45 -0
  8. package/.github/workflows/claude.yml +46 -0
  9. package/.github/workflows/macos.yml +77 -58
  10. package/.github/workflows/release.yml +165 -0
  11. package/.github/workflows/ubuntu.yml +87 -70
  12. package/.github/workflows/windows.yml +81 -64
  13. package/.husky/pre-commit +1 -0
  14. package/.lintstagedrc.json +6 -0
  15. package/.node-version +1 -1
  16. package/.postcssrc.json +5 -0
  17. package/.prettierignore +8 -0
  18. package/.prettierrc +18 -0
  19. package/.vscode/launch.json +42 -45
  20. package/.vscode/tasks.json +48 -48
  21. package/CODE_OF_CONDUCT.md +128 -45
  22. package/HOW_TO.md +39 -0
  23. package/LICENSE.md +7 -0
  24. package/README.md +103 -111
  25. package/angular.json +166 -194
  26. package/app/Application.js +39 -39
  27. package/app/Application.ts +38 -38
  28. package/app/config/alert.ts +31 -31
  29. package/app/config/database.js +194 -202
  30. package/app/config/database.ts +194 -202
  31. package/app/config/index.js +19 -19
  32. package/app/config/index.ts +2 -2
  33. package/app/config/mimes.js +48 -48
  34. package/app/config/mimes.ts +53 -53
  35. package/app/config/system.js +578 -496
  36. package/app/config/system.ts +580 -498
  37. package/app/config/themes.ts +38 -38
  38. package/app/core/AppLogger.js +30 -30
  39. package/app/core/AppLogger.ts +37 -37
  40. package/app/core/ConfigManager.js +129 -113
  41. package/app/core/ConfigManager.ts +150 -137
  42. package/app/core/ConnectionManager.js +93 -82
  43. package/app/core/ConnectionManager.ts +107 -95
  44. package/app/core/FontCatalog.js +32 -50
  45. package/app/core/FontCatalog.ts +20 -42
  46. package/app/core/FontFinder.js +72 -85
  47. package/app/core/FontFinder.ts +75 -96
  48. package/app/core/FontManager.js +128 -164
  49. package/app/core/FontManager.ts +136 -172
  50. package/app/core/FontObject.js +53 -53
  51. package/app/core/FontObject.ts +62 -62
  52. package/app/core/MessageHandler.js +270 -271
  53. package/app/core/MessageHandler.ts +330 -337
  54. package/app/core/SystemManager.js +132 -139
  55. package/app/core/SystemManager.ts +160 -171
  56. package/app/core/menu/Example.ts +279 -279
  57. package/app/core/menu/MenuBuilder.js +43 -44
  58. package/app/core/menu/MenuBuilder.ts +51 -53
  59. package/app/core/menu/templates/DarwinTemplate.js +124 -126
  60. package/app/core/menu/templates/DarwinTemplate.ts +144 -142
  61. package/app/core/menu/templates/SystemTemplate.js +121 -123
  62. package/app/core/menu/templates/SystemTemplate.ts +136 -139
  63. package/app/database/entity/Collection.schema.js +98 -98
  64. package/app/database/entity/Collection.schema.ts +68 -68
  65. package/app/database/entity/Logger.schema.js +49 -49
  66. package/app/database/entity/Logger.schema.ts +26 -26
  67. package/app/database/entity/Store.schema.js +159 -164
  68. package/app/database/entity/Store.schema.ts +110 -116
  69. package/app/database/entity/index.js +19 -19
  70. package/app/database/entity/index.ts +2 -2
  71. package/app/database/repository/Collection.repository.js +277 -180
  72. package/app/database/repository/Collection.repository.ts +291 -190
  73. package/app/database/repository/Logger.repository.js +24 -24
  74. package/app/database/repository/Logger.repository.ts +10 -10
  75. package/app/database/repository/Store.repository.js +324 -327
  76. package/app/database/repository/Store.repository.ts +349 -358
  77. package/app/database/repository/User.repository.js +11 -11
  78. package/app/database/repository/User.repository.ts +8 -8
  79. package/app/database/repository/index.js +19 -19
  80. package/app/database/repository/index.ts +2 -2
  81. package/app/enums/ChannelType.js +62 -61
  82. package/app/enums/ChannelType.ts +67 -65
  83. package/app/enums/StorageType.js +19 -18
  84. package/app/enums/{storageType.ts → StorageType.ts} +15 -14
  85. package/app/enums/index.js +18 -18
  86. package/app/enums/index.ts +2 -2
  87. package/app/helpers/command.js +27 -27
  88. package/app/helpers/command.ts +19 -19
  89. package/app/helpers/random.js +15 -15
  90. package/app/helpers/random.ts +12 -12
  91. package/app/main.js +97 -81
  92. package/app/main.ts +114 -94
  93. package/app/package-lock.json +2240 -2649
  94. package/app/package.json +23 -35
  95. package/app/types/AppAlert.js +2 -2
  96. package/app/types/AppAlert.ts +8 -8
  97. package/app/types/AuthUser.js +6 -6
  98. package/app/types/AuthUser.ts +5 -5
  99. package/app/types/Breadcrumb.js +2 -2
  100. package/app/types/Breadcrumb.ts +4 -4
  101. package/app/types/FontMetrics.ts +7 -0
  102. package/app/types/ImportOptions.js +6 -6
  103. package/app/types/ImportOptions.ts +3 -3
  104. package/app/types/QueryOptions.js +2 -2
  105. package/app/types/QueryOptions.ts +12 -12
  106. package/app/types/SystemConfig.js +2 -2
  107. package/app/types/SystemConfig.ts +127 -132
  108. package/app/types/SystemStats.js +2 -2
  109. package/app/types/SystemStats.ts +6 -7
  110. package/app/types/SystemTheme.js +2 -2
  111. package/app/types/SystemTheme.ts +5 -5
  112. package/app/types/index.js +24 -24
  113. package/app/types/index.ts +9 -8
  114. package/commitlint.config.mjs +3 -0
  115. package/e2e/main.spec.ts +57 -59
  116. package/e2e/playwright.config.ts +20 -19
  117. package/e2e/tsconfig.e2e.json +13 -13
  118. package/electron-builder.json +34 -71
  119. package/eslint.config.mjs +111 -0
  120. package/package.json +122 -121
  121. package/src/app/app.component.html +1 -1
  122. package/src/app/app.component.spec.ts +21 -0
  123. package/src/app/app.component.ts +40 -37
  124. package/src/app/core/core.module.ts +8 -11
  125. package/src/app/core/services/database/database.service.ts +410 -286
  126. package/src/app/core/services/electron/electron.service.spec.ts +12 -12
  127. package/src/app/core/services/electron/electron.service.ts +62 -62
  128. package/src/app/core/services/index.ts +5 -14
  129. package/src/app/core/services/message/message.service.ts +291 -289
  130. package/src/app/core/services/news/news.service.ts +52 -94
  131. package/src/app/core/services/presentation/presentation.service.ts +253 -341
  132. package/src/app/home/home.component.html +7 -0
  133. package/src/app/home/home.component.spec.ts +31 -0
  134. package/src/app/home/home.component.ts +15 -0
  135. package/src/app/layout/aside/aside.component.html +35 -9
  136. package/src/app/layout/aside/aside.component.ts +60 -26
  137. package/src/app/layout/footer/footer.component.html +5 -11
  138. package/src/app/layout/footer/footer.component.ts +13 -32
  139. package/src/app/layout/header/header.component.html +118 -35
  140. package/src/app/layout/header/header.component.ts +52 -229
  141. package/src/app/layout/layout.component.html +32 -14
  142. package/src/app/layout/layout.component.ts +19 -23
  143. package/src/app/layout/main/main.component.html +46 -0
  144. package/src/app/layout/main/main.component.ts +20 -0
  145. package/src/app/layout/navigation/library/library.component.ts +51 -0
  146. package/src/app/layout/navigation/navigation.component.html +126 -142
  147. package/src/app/layout/navigation/navigation.component.ts +372 -302
  148. package/src/app/layout/navigation/stats/stats.component.ts +56 -0
  149. package/src/app/settings/ai-keys/ai-keys.component.html +56 -0
  150. package/src/app/settings/ai-keys/ai-keys.component.ts +44 -0
  151. package/src/app/settings/danger-zone/danger-zone.component.html +22 -0
  152. package/src/app/settings/danger-zone/danger-zone.component.ts +37 -0
  153. package/src/app/settings/logs/logs.component.html +41 -0
  154. package/src/app/settings/logs/logs.component.ts +43 -0
  155. package/src/app/settings/news-api/news-api.component.html +40 -0
  156. package/src/app/settings/news-api/news-api.component.ts +57 -0
  157. package/src/app/settings/pages/general/general.component.html +7 -0
  158. package/src/app/settings/pages/general/general.component.ts +20 -0
  159. package/src/app/settings/pages/logs/logs.component.html +1 -0
  160. package/src/app/settings/pages/logs/logs.component.ts +10 -0
  161. package/src/app/settings/pages/system/system.component.html +1 -0
  162. package/src/app/settings/pages/system/system.component.ts +10 -0
  163. package/src/app/settings/quick-actions/quick-actions.component.html +49 -0
  164. package/src/app/settings/quick-actions/quick-actions.component.ts +40 -0
  165. package/src/app/settings/settings.component.html +47 -0
  166. package/src/app/settings/settings.component.ts +10 -0
  167. package/src/app/settings/system-info/system-info.component.html +21 -0
  168. package/src/app/settings/system-info/system-info.component.ts +42 -0
  169. package/src/app/settings/theme/theme.component.html +15 -0
  170. package/src/app/settings/theme/theme.component.ts +22 -0
  171. package/src/app/shared/components/collapsible-panel/collapsible-panel.component.ts +43 -0
  172. package/src/app/shared/components/context-menu/context-menu.component.ts +67 -0
  173. package/src/app/shared/components/datagrid/datagrid.component.html +96 -0
  174. package/src/app/shared/components/datagrid/datagrid.component.ts +49 -0
  175. package/src/app/shared/components/index.ts +11 -16
  176. package/src/app/shared/components/inspector/inspector.component.html +140 -0
  177. package/src/app/shared/components/inspector/inspector.component.ts +41 -0
  178. package/src/app/shared/components/page-not-found/page-not-found.component.html +1 -3
  179. package/src/app/shared/components/page-not-found/page-not-found.component.spec.ts +22 -0
  180. package/src/app/shared/components/page-not-found/page-not-found.component.ts +14 -12
  181. package/src/app/shared/components/panel/panel.component.html +5 -0
  182. package/src/app/shared/components/panel/panel.component.ts +8 -0
  183. package/src/app/shared/components/preview/preview.component.html +36 -0
  184. package/src/app/shared/components/preview/preview.component.ts +68 -0
  185. package/src/app/shared/components/prompt-dialog/prompt-dialog.component.html +36 -0
  186. package/src/app/shared/components/prompt-dialog/prompt-dialog.component.ts +39 -0
  187. package/src/app/shared/components/search/search.component.html +329 -54
  188. package/src/app/shared/components/search/search.component.ts +221 -77
  189. package/src/app/shared/components/spinner/spinner.component.ts +10 -26
  190. package/src/app/shared/components/toolbar/toolbar.component.html +207 -0
  191. package/src/app/shared/components/toolbar/toolbar.component.ts +99 -0
  192. package/src/app/shared/components/waterfall/waterfall.component.html +119 -0
  193. package/src/app/shared/components/waterfall/waterfall.component.ts +119 -0
  194. package/src/app/shared/directives/autofocus/autofocus.directive.ts +14 -0
  195. package/src/app/shared/directives/index.ts +2 -2
  196. package/src/app/shared/directives/webview/webview.directive.spec.ts +8 -0
  197. package/src/app/shared/directives/webview/webview.directive.ts +9 -8
  198. package/src/app/shared/shared.module.ts +13 -92
  199. package/src/assets/background.jpg +0 -0
  200. package/src/assets/fonts/md/MaterialIcons-Regular.woff2 +0 -0
  201. package/src/assets/fonts/md/MaterialSymbolsOutlined.woff2 +0 -0
  202. package/src/assets/i18n/en.json +12 -12
  203. package/src/assets/icons/electron.bmp +0 -0
  204. package/src/assets/icons/favicon.256x256.png +0 -0
  205. package/src/assets/icons/favicon.512x512.png +0 -0
  206. package/src/assets/icons/favicon.icns +0 -0
  207. package/src/assets/icons/favicon.ico +0 -0
  208. package/src/assets/icons/favicon.png +0 -0
  209. package/src/environments/environment.dev.ts +4 -4
  210. package/src/environments/environment.prod.ts +4 -4
  211. package/src/environments/environment.ts +4 -4
  212. package/src/favicon.ico +0 -0
  213. package/src/index.html +19 -55
  214. package/src/main.ts +65 -15
  215. package/src/styles/base/reset.css +41 -0
  216. package/src/styles/base/variables.css +356 -0
  217. package/src/styles/components/buttons.css +108 -0
  218. package/src/styles/components/cards.css +60 -0
  219. package/src/styles/components/forms.css +70 -0
  220. package/src/styles/components/navigation.css +24 -0
  221. package/src/styles/components/scrollbox.css +50 -0
  222. package/src/styles/components/spinner.css +7 -0
  223. package/src/styles/components/splash.css +47 -0
  224. package/src/styles/components/toolbar.css +92 -0
  225. package/src/styles/fonts/md.css +39 -0
  226. package/src/styles/themes/dashboard.scss +293 -294
  227. package/src/styles/themes/euphoria.scss +284 -283
  228. package/src/styles/themes/mellow.scss +281 -280
  229. package/src/styles/themes/midnight.scss +284 -283
  230. package/src/styles/themes/passion.scss +281 -280
  231. package/src/styles/themes/swiss.scss +284 -283
  232. package/src/styles.css +17 -0
  233. package/src/tsconfig.app.json +11 -20
  234. package/src/tsconfig.spec.json +10 -23
  235. package/src/typings.d.ts +9 -9
  236. package/src/vitest.d.ts +1 -0
  237. package/tsconfig.json +38 -42
  238. package/tsconfig.serve.json +27 -27
  239. package/.eslintrc.json +0 -54
  240. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -29
  241. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
  242. package/.github/stale.yml +0 -17
  243. package/CONTRIBUTING.md +0 -72
  244. package/LICENSE +0 -21
  245. package/angular.webpack.js +0 -32
  246. package/app/core/FontInstaller.js +0 -67
  247. package/app/core/FontInstaller.ts +0 -63
  248. package/docs/logo.png +0 -0
  249. package/docs/screenshots/readme.md +0 -7
  250. package/docs/screenshots/screen-grab1.png +0 -0
  251. package/docs/screenshots/screen-grab2.png +0 -0
  252. package/docs/screenshots/screen-grab3.png +0 -0
  253. package/src/app/app-routing.module.ts +0 -15
  254. package/src/app/app.component.scss +0 -0
  255. package/src/app/app.component.spec.ts.dist +0 -33
  256. package/src/app/app.module.ts +0 -63
  257. package/src/app/core/model/AuthUserModel.ts +0 -7
  258. package/src/app/core/model/CustomThemeModel.ts +0 -7
  259. package/src/app/core/model/DbConnectionModel.ts +0 -16
  260. package/src/app/core/model/ImportOptionsModel.ts +0 -5
  261. package/src/app/core/model/LatestNewsModel.ts +0 -7
  262. package/src/app/core/model/SearchFormModel.ts +0 -10
  263. package/src/app/core/model/index.ts +0 -6
  264. package/src/app/core/services/alert/alert.service.spec.ts +0 -22
  265. package/src/app/core/services/alert/alert.service.ts +0 -71
  266. package/src/app/core/services/auth/auth.service.ts +0 -30
  267. package/src/app/core/services/boot/boot.service.ts +0 -33
  268. package/src/app/core/services/breadcrumb/breadcrumb.service.spec.ts +0 -22
  269. package/src/app/core/services/breadcrumb/breadcrumb.service.ts +0 -30
  270. package/src/app/core/services/config/config.service.ts +0 -63
  271. package/src/app/core/services/font/font.service.ts +0 -79
  272. package/src/app/core/services/gravatar/gravatar.service.spec.ts +0 -16
  273. package/src/app/core/services/gravatar/gravatar.service.ts +0 -18
  274. package/src/app/core/services/modal/modal.service.spec.ts +0 -16
  275. package/src/app/core/services/modal/modal.service.ts +0 -34
  276. package/src/app/core/services/utils/utils.service.spec.ts +0 -12
  277. package/src/app/core/services/utils/utils.service.ts +0 -144
  278. package/src/app/layout/aside/aside.component.scss +0 -1
  279. package/src/app/layout/footer/footer.component.scss +0 -27
  280. package/src/app/layout/header/header.component.scss +0 -60
  281. package/src/app/layout/layout.component.scss +0 -119
  282. package/src/app/layout/layout.module.ts +0 -32
  283. package/src/app/layout/layout.service.ts +0 -13
  284. package/src/app/layout/navigation/navigation.component.scss +0 -0
  285. package/src/app/pages/main/grid/grid.component.html +0 -160
  286. package/src/app/pages/main/grid/grid.component.scss +0 -3
  287. package/src/app/pages/main/grid/grid.component.ts +0 -98
  288. package/src/app/pages/main/inspect/inspect.component.html +0 -7
  289. package/src/app/pages/main/inspect/inspect.component.scss +0 -3
  290. package/src/app/pages/main/inspect/inspect.component.ts +0 -66
  291. package/src/app/pages/main/main-routing.module.ts +0 -30
  292. package/src/app/pages/main/main.component.html +0 -6
  293. package/src/app/pages/main/main.component.scss +0 -191
  294. package/src/app/pages/main/main.component.ts +0 -35
  295. package/src/app/pages/main/main.module.ts +0 -28
  296. package/src/app/pages/main/preview/preview.component.html +0 -46
  297. package/src/app/pages/main/preview/preview.component.scss +0 -0
  298. package/src/app/pages/main/preview/preview.component.ts +0 -239
  299. package/src/app/pages/main/toolbar/toolbar.component.html +0 -78
  300. package/src/app/pages/main/toolbar/toolbar.component.scss +0 -3
  301. package/src/app/pages/main/toolbar/toolbar.component.ts +0 -132
  302. package/src/app/shared/components/alert/alert.component.html +0 -9
  303. package/src/app/shared/components/alert/alert.component.scss +0 -0
  304. package/src/app/shared/components/alert/alert.component.ts +0 -37
  305. package/src/app/shared/components/breadcrumbs/breadcrumbs.component.html +0 -14
  306. package/src/app/shared/components/breadcrumbs/breadcrumbs.component.scss +0 -0
  307. package/src/app/shared/components/breadcrumbs/breadcrumbs.component.ts +0 -36
  308. package/src/app/shared/components/button/button.component.html +0 -3
  309. package/src/app/shared/components/button/button.component.scss +0 -2
  310. package/src/app/shared/components/button/button.component.ts +0 -22
  311. package/src/app/shared/components/collection/create-collection/create-collection.component.html +0 -41
  312. package/src/app/shared/components/collection/create-collection/create-collection.component.scss +0 -0
  313. package/src/app/shared/components/collection/create-collection/create-collection.component.ts +0 -68
  314. package/src/app/shared/components/collection/form-collection/form-collection.component.html +0 -1
  315. package/src/app/shared/components/collection/form-collection/form-collection.component.scss +0 -0
  316. package/src/app/shared/components/collection/form-collection/form-collection.component.ts +0 -15
  317. package/src/app/shared/components/collection/update-collection/update-collection.component.html +0 -40
  318. package/src/app/shared/components/collection/update-collection/update-collection.component.scss +0 -0
  319. package/src/app/shared/components/collection/update-collection/update-collection.component.ts +0 -71
  320. package/src/app/shared/components/glyph-list/glyph-list.component.html +0 -40
  321. package/src/app/shared/components/glyph-list/glyph-list.component.scss +0 -1
  322. package/src/app/shared/components/glyph-list/glyph-list.component.ts +0 -165
  323. package/src/app/shared/components/glyph-view/glyph-view.component.html +0 -23
  324. package/src/app/shared/components/glyph-view/glyph-view.component.scss +0 -0
  325. package/src/app/shared/components/glyph-view/glyph-view.component.ts +0 -228
  326. package/src/app/shared/components/loading/loading.component.html +0 -1
  327. package/src/app/shared/components/loading/loading.component.scss +0 -0
  328. package/src/app/shared/components/loading/loading.component.ts +0 -26
  329. package/src/app/shared/components/modal/modal.component.html +0 -31
  330. package/src/app/shared/components/modal/modal.component.scss +0 -0
  331. package/src/app/shared/components/modal/modal.component.ts +0 -51
  332. package/src/app/shared/components/page-not-found/page-not-found.component.scss +0 -0
  333. package/src/app/shared/components/paginator/paginator.component.html +0 -21
  334. package/src/app/shared/components/paginator/paginator.component.scss +0 -3
  335. package/src/app/shared/components/paginator/paginator.component.ts +0 -133
  336. package/src/app/shared/components/pairing/pairing.component.html +0 -20
  337. package/src/app/shared/components/pairing/pairing.component.scss +0 -0
  338. package/src/app/shared/components/pairing/pairing.component.ts +0 -33
  339. package/src/app/shared/components/search/search.component.scss +0 -10
  340. package/src/app/shared/components/settings/database/database.component.html +0 -151
  341. package/src/app/shared/components/settings/database/database.component.scss +0 -0
  342. package/src/app/shared/components/settings/database/database.component.ts +0 -145
  343. package/src/app/shared/components/settings/general/general.component.html +0 -170
  344. package/src/app/shared/components/settings/general/general.component.scss +0 -0
  345. package/src/app/shared/components/settings/general/general.component.ts +0 -150
  346. package/src/app/shared/components/settings/logs/logs.component.html +0 -44
  347. package/src/app/shared/components/settings/logs/logs.component.scss +0 -0
  348. package/src/app/shared/components/settings/logs/logs.component.ts +0 -37
  349. package/src/app/shared/components/settings/news/news.component.html +0 -41
  350. package/src/app/shared/components/settings/news/news.component.scss +0 -0
  351. package/src/app/shared/components/settings/news/news.component.ts +0 -52
  352. package/src/app/shared/components/settings/settings.component.html +0 -46
  353. package/src/app/shared/components/settings/settings.component.scss +0 -0
  354. package/src/app/shared/components/settings/settings.component.ts +0 -23
  355. package/src/app/shared/components/settings/system/system.component.html +0 -30
  356. package/src/app/shared/components/settings/system/system.component.scss +0 -0
  357. package/src/app/shared/components/settings/system/system.component.ts +0 -43
  358. package/src/app/shared/components/settings/theme/theme.component.html +0 -22
  359. package/src/app/shared/components/settings/theme/theme.component.scss +0 -0
  360. package/src/app/shared/components/settings/theme/theme.component.ts +0 -50
  361. package/src/app/shared/components/spinner/spinner.component.html +0 -1
  362. package/src/app/shared/components/spinner/spinner.component.scss +0 -0
  363. package/src/app/shared/components/store/store.component.html +0 -22
  364. package/src/app/shared/components/store/store.component.scss +0 -10
  365. package/src/app/shared/components/store/store.component.ts +0 -58
  366. package/src/app/shared/components/tables/tables.component.html +0 -47
  367. package/src/app/shared/components/tables/tables.component.scss +0 -10
  368. package/src/app/shared/components/tables/tables.component.ts +0 -81
  369. package/src/app/shared/components/typescale/typescale.component.html +0 -53
  370. package/src/app/shared/components/typescale/typescale.component.scss +0 -0
  371. package/src/app/shared/components/typescale/typescale.component.ts +0 -168
  372. package/src/app/shared/directives/gravatar/gravatar.directive.ts +0 -29
  373. package/src/app/shared/pipes/installable.pipe.ts +0 -10
  374. package/src/app/shared/pipes/prettybytes.pipe.ts +0 -10
  375. package/src/app/shared/pipes/safehtml.pipe.ts +0 -10
  376. package/src/assets/fonts/fa/fa-brands-400.eot +0 -0
  377. package/src/assets/fonts/fa/fa-brands-400.svg +0 -3535
  378. package/src/assets/fonts/fa/fa-brands-400.ttf +0 -0
  379. package/src/assets/fonts/fa/fa-brands-400.woff +0 -0
  380. package/src/assets/fonts/fa/fa-brands-400.woff2 +0 -0
  381. package/src/assets/fonts/fa/fa-regular-400.eot +0 -0
  382. package/src/assets/fonts/fa/fa-regular-400.svg +0 -803
  383. package/src/assets/fonts/fa/fa-regular-400.ttf +0 -0
  384. package/src/assets/fonts/fa/fa-regular-400.woff +0 -0
  385. package/src/assets/fonts/fa/fa-regular-400.woff2 +0 -0
  386. package/src/assets/fonts/fa/fa-solid-900.eot +0 -0
  387. package/src/assets/fonts/fa/fa-solid-900.svg +0 -4700
  388. package/src/assets/fonts/fa/fa-solid-900.ttf +0 -0
  389. package/src/assets/fonts/fa/fa-solid-900.woff +0 -0
  390. package/src/assets/fonts/fa/fa-solid-900.woff2 +0 -0
  391. package/src/assets/fonts/md/MaterialIcons-Regular.eot +0 -0
  392. package/src/assets/fonts/md/MaterialIcons-Regular.ijmap +0 -1
  393. package/src/assets/fonts/md/MaterialIcons-Regular.svg +0 -2373
  394. package/src/assets/fonts/md/MaterialIcons-Regular.ttf +0 -0
  395. package/src/assets/fonts/md/MaterialIcons-Regular.woff +0 -0
  396. package/src/assets/fonts/md/README.md +0 -9
  397. package/src/assets/fonts/md/codepoints +0 -932
  398. package/src/assets/fonts/md/material-icons.css +0 -36
  399. package/src/assets/fonts/octicon/octicon.eot +0 -0
  400. package/src/assets/fonts/octicon/octicon.svg +0 -378
  401. package/src/assets/fonts/octicon/octicon.ttf +0 -0
  402. package/src/assets/fonts/octicon/octicon.woff +0 -0
  403. package/src/assets/fonts/octicon/octicon.woff2 +0 -0
  404. package/src/assets/fonts/roboto/Roboto-Bold-webfont.eot +0 -0
  405. package/src/assets/fonts/roboto/Roboto-Bold-webfont.svg +0 -607
  406. package/src/assets/fonts/roboto/Roboto-Bold-webfont.ttf +0 -0
  407. package/src/assets/fonts/roboto/Roboto-Bold-webfont.woff +0 -0
  408. package/src/assets/fonts/roboto/Roboto-Medium-webfont.eot +0 -0
  409. package/src/assets/fonts/roboto/Roboto-Medium-webfont.svg +0 -607
  410. package/src/assets/fonts/roboto/Roboto-Medium-webfont.ttf +0 -0
  411. package/src/assets/fonts/roboto/Roboto-Medium-webfont.woff +0 -0
  412. package/src/assets/fonts/roboto/Roboto-Regular-webfont.eot +0 -0
  413. package/src/assets/fonts/roboto/Roboto-Regular-webfont.svg +0 -635
  414. package/src/assets/fonts/roboto/Roboto-Regular-webfont.ttf +0 -0
  415. package/src/assets/fonts/roboto/Roboto-Regular-webfont.woff +0 -0
  416. package/src/assets/icons/android-chrome-192x192.png +0 -0
  417. package/src/assets/icons/android-chrome-512x512.png +0 -0
  418. package/src/assets/icons/apple-touch-icon.png +0 -0
  419. package/src/assets/icons/favicon-16x16.png +0 -0
  420. package/src/assets/icons/favicon-32x32.png +0 -0
  421. package/src/assets/icons/site.webmanifest +0 -1
  422. package/src/assets/images/electron.bmp +0 -0
  423. package/src/bin/activator +0 -0
  424. package/src/bin/activator.exe +0 -0
  425. package/src/environments/environment.web.prod.ts +0 -4
  426. package/src/environments/environment.web.ts +0 -4
  427. package/src/karma.conf.js +0 -50
  428. package/src/polyfills-test.ts +0 -1
  429. package/src/polyfills.ts +0 -53
  430. package/src/styles/base/loading.scss +0 -87
  431. package/src/styles/base/reset.scss +0 -408
  432. package/src/styles/components/alert.scss +0 -54
  433. package/src/styles/components/buttons.scss +0 -93
  434. package/src/styles/components/forms.scss +0 -96
  435. package/src/styles/components/inputs.scss +0 -113
  436. package/src/styles/components/modal.scss +0 -52
  437. package/src/styles/components/paginator.scss +0 -108
  438. package/src/styles/components/scrollbox.scss +0 -71
  439. package/src/styles/components/spinner.scss +0 -11
  440. package/src/styles/components/tables.scss +0 -42
  441. package/src/styles/components/tabs.scss +0 -44
  442. package/src/styles/components/toolbar.scss +0 -130
  443. package/src/styles/fonts/md.scss +0 -54
  444. package/src/styles/fonts/octicons.scss +0 -1351
  445. package/src/styles/fonts/roboto.scss +0 -32
  446. package/src/styles/tools/_functions.scss +0 -5
  447. package/src/styles/tools/_mixins.scss +0 -159
  448. package/src/styles/tools/_placeholders.scss +0 -17
  449. package/src/styles/tools/_variables.scss +0 -67
  450. package/src/styles.scss +0 -37
  451. package/src/test.ts +0 -22
  452. package/tailwind.config.js +0 -67
@@ -0,0 +1,56 @@
1
+ import { Component, inject } from '@angular/core';
2
+ import { NewsService } from '../../../core/services';
3
+ import { CollapsiblePanelComponent } from '../../../shared/components/collapsible-panel/collapsible-panel.component';
4
+
5
+ @Component({
6
+ selector: 'app-news-stats',
7
+ standalone: true,
8
+ imports: [CollapsiblePanelComponent],
9
+ template: `
10
+ @if (news.hasArticles()) {
11
+ <app-collapsible-panel title="News">
12
+ <ul class="flex flex-col py-0.5">
13
+ <li class="flex items-center px-3.5 py-1 text-xs font-normal">
14
+ <span
15
+ class="material-symbols-outlined icon-sm mr-2"
16
+ style="font-variation-settings: 'opsz' 20, 'wght' 300; color: var(--text-muted)"
17
+ >article</span
18
+ >
19
+ <span class="flex-1">Total Articles</span>
20
+ <span class="text-[11px]" style="color: var(--text-muted)">{{ news.articleCount() }}</span>
21
+ </li>
22
+ <li class="flex items-center px-3.5 py-1 text-xs font-normal">
23
+ <span
24
+ class="material-symbols-outlined icon-sm mr-2"
25
+ style="font-variation-settings: 'opsz' 20, 'wght' 300; color: var(--text-muted)"
26
+ >source</span
27
+ >
28
+ <span class="flex-1">Sources</span>
29
+ <span class="text-[11px]" style="color: var(--text-muted)">{{ news.sourceCount() }}</span>
30
+ </li>
31
+ <li class="flex items-center px-3.5 py-1 text-xs font-normal">
32
+ <span
33
+ class="material-symbols-outlined icon-sm mr-2"
34
+ style="font-variation-settings: 'opsz' 20, 'wght' 300; color: var(--text-muted)"
35
+ >person</span
36
+ >
37
+ <span class="flex-1">Authors</span>
38
+ <span class="text-[11px]" style="color: var(--text-muted)">{{ news.authorCount() }}</span>
39
+ </li>
40
+ <li class="flex items-center px-3.5 py-1 text-xs font-normal">
41
+ <span
42
+ class="material-symbols-outlined icon-sm mr-2"
43
+ style="font-variation-settings: 'opsz' 20, 'wght' 300; color: var(--text-muted)"
44
+ >schedule</span
45
+ >
46
+ <span class="flex-1">Last Fetched</span>
47
+ <span class="text-[11px]" style="color: var(--text-muted)">{{ news.lastFetched() }}</span>
48
+ </li>
49
+ </ul>
50
+ </app-collapsible-panel>
51
+ }
52
+ `,
53
+ })
54
+ export class NewsStatsComponent {
55
+ readonly news = inject(NewsService);
56
+ }
@@ -0,0 +1,56 @@
1
+ <div class="card">
2
+ <div class="card-header">
3
+ <div class="card-title"><h3>AI API Keys</h3></div>
4
+ </div>
5
+ <div class="card-body space-y-4">
6
+ <div>
7
+ <label class="form-label" for="anthropicKey">Anthropic</label>
8
+ <input
9
+ type="password"
10
+ id="anthropicKey"
11
+ class="form-input w-full"
12
+ [ngModel]="anthropicKey()"
13
+ (ngModelChange)="anthropicKey.set($event)"
14
+ name="anthropicKey"
15
+ placeholder="sk-ant-..."
16
+ autocomplete="off"
17
+ />
18
+ </div>
19
+ <div>
20
+ <label class="form-label" for="googleKey">Google Gemini</label>
21
+ <input
22
+ type="password"
23
+ id="googleKey"
24
+ class="form-input w-full"
25
+ [ngModel]="googleKey()"
26
+ (ngModelChange)="googleKey.set($event)"
27
+ name="googleKey"
28
+ placeholder="AIza..."
29
+ autocomplete="off"
30
+ />
31
+ </div>
32
+ <div>
33
+ <label class="form-label" for="openaiKey">OpenAI</label>
34
+ <input
35
+ type="password"
36
+ id="openaiKey"
37
+ class="form-input w-full"
38
+ [ngModel]="openaiKey()"
39
+ (ngModelChange)="openaiKey.set($event)"
40
+ name="openaiKey"
41
+ placeholder="sk-..."
42
+ autocomplete="off"
43
+ />
44
+ </div>
45
+ </div>
46
+ <div class="card-footer">
47
+ <div>
48
+ @if (saveStatus() === 'saved') {
49
+ <span class="text-xs" [style.color]="'var(--text-muted)'">Keys saved.</span>
50
+ }
51
+ </div>
52
+ <div class="card-tools">
53
+ <button class="btn btn-sm btn-theme" (click)="onSave()">Save</button>
54
+ </div>
55
+ </div>
56
+ </div>
@@ -0,0 +1,44 @@
1
+ import { Component, inject, signal, OnInit } from '@angular/core';
2
+ import { FormsModule } from '@angular/forms';
3
+ import { MessageService } from '../../core/services';
4
+ import { StorageType } from '@main/enums';
5
+
6
+ interface AiKeys {
7
+ anthropic: string;
8
+ google: string;
9
+ openai: string;
10
+ }
11
+
12
+ @Component({
13
+ selector: 'app-settings-ai-keys',
14
+ standalone: true,
15
+ imports: [FormsModule],
16
+ templateUrl: './ai-keys.component.html',
17
+ })
18
+ export class SettingsAiKeysComponent implements OnInit {
19
+ private readonly message = inject(MessageService);
20
+
21
+ readonly anthropicKey = signal('');
22
+ readonly googleKey = signal('');
23
+ readonly openaiKey = signal('');
24
+ readonly saveStatus = signal<'idle' | 'saved'>('idle');
25
+
26
+ async ngOnInit() {
27
+ const keys = (await this.message.get(StorageType.AiKeys, null)) as AiKeys | null;
28
+ if (keys) {
29
+ this.anthropicKey.set(keys.anthropic ?? '');
30
+ this.googleKey.set(keys.google ?? '');
31
+ this.openaiKey.set(keys.openai ?? '');
32
+ }
33
+ }
34
+
35
+ async onSave() {
36
+ await this.message.set(StorageType.AiKeys, {
37
+ anthropic: this.anthropicKey(),
38
+ google: this.googleKey(),
39
+ openai: this.openaiKey(),
40
+ });
41
+ this.saveStatus.set('saved');
42
+ setTimeout(() => this.saveStatus.set('idle'), 2000);
43
+ }
44
+ }
@@ -0,0 +1,22 @@
1
+ <div class="card" style="border-color: #dc2626">
2
+ <div class="card-header" style="border-color: #dc2626">
3
+ <div class="card-title"><h3 style="color: #dc2626">Danger Zone</h3></div>
4
+ </div>
5
+ <div class="card-body space-y-4">
6
+ <div class="flex items-center justify-between">
7
+ <div>
8
+ <p class="text-xs font-semibold" [style.color]="'var(--text-primary)'">Drop active database</p>
9
+ <p class="text-xs" [style.color]="'var(--text-muted)'">Drops the database and all its data.</p>
10
+ </div>
11
+ <button class="btn btn-sm btn-danger" (click)="onDropDatabase()">Drop</button>
12
+ </div>
13
+
14
+ <div class="flex items-center justify-between">
15
+ <div>
16
+ <p class="text-xs font-semibold" [style.color]="'var(--text-primary)'">Clear system storage</p>
17
+ <p class="text-xs" [style.color]="'var(--text-muted)'">Removes all settings from system store.</p>
18
+ </div>
19
+ <button class="btn btn-sm btn-danger" (click)="onClearStore()">Clear</button>
20
+ </div>
21
+ </div>
22
+ </div>
@@ -0,0 +1,37 @@
1
+ import { Component, inject } from '@angular/core';
2
+ import { MessageService } from '../../core/services';
3
+
4
+ @Component({
5
+ selector: 'app-settings-danger-zone',
6
+ standalone: true,
7
+ templateUrl: './danger-zone.component.html',
8
+ })
9
+ export class SettingsDangerZoneComponent {
10
+ private readonly message = inject(MessageService);
11
+
12
+ async onDropDatabase() {
13
+ const response = await this.message.showMessageBox({
14
+ type: 'question',
15
+ buttons: ['Yes', 'No'],
16
+ title: 'Confirm',
17
+ message: 'Are you sure you want to drop the database?',
18
+ });
19
+ if (response?.response === 0) {
20
+ await this.message.dropDatabase();
21
+ this.message.reloadWindow();
22
+ }
23
+ }
24
+
25
+ async onClearStore() {
26
+ const response = await this.message.showMessageBox({
27
+ type: 'question',
28
+ buttons: ['Yes', 'No'],
29
+ title: 'Confirm',
30
+ message: 'Are you sure you want to delete the application store?',
31
+ });
32
+ if (response?.response === 0) {
33
+ await this.message.clearStore();
34
+ this.message.reloadWindow();
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,41 @@
1
+ <div class="card">
2
+ <div class="card-header">
3
+ <div class="card-title"><h3>System Logs</h3></div>
4
+ <div class="card-tools">
5
+ <button class="btn btn-sm btn-default" (click)="onTruncateLogs()">Clear All</button>
6
+ </div>
7
+ </div>
8
+ <div class="card-body p-0">
9
+ @if (logs().length) {
10
+ <table class="w-full text-xs" [style.color]="'var(--text-primary)'">
11
+ <thead>
12
+ <tr [style.border-bottom]="'1px solid var(--border-subtle)'">
13
+ <th class="text-left px-4 py-2 font-semibold" [style.color]="'var(--text-secondary)'">Message</th>
14
+ <th class="text-center px-4 py-2 font-semibold w-24" [style.color]="'var(--text-secondary)'">Status</th>
15
+ <th class="text-center px-4 py-2 font-semibold w-40" [style.color]="'var(--text-secondary)'">Created</th>
16
+ <th class="text-center px-4 py-2 font-semibold w-16" [style.color]="'var(--text-secondary)'"></th>
17
+ </tr>
18
+ </thead>
19
+ <tbody>
20
+ @for (item of logs(); track item.id) {
21
+ <tr [style.border-bottom]="'1px solid var(--border-subtle)'">
22
+ <td class="px-4 py-2">
23
+ <span class="font-semibold">{{ filterMessageType(item.type) }}</span>
24
+ <span class="ml-2" [style.color]="'var(--text-muted)'">{{ item.message.substring(0, 80) }}</span>
25
+ </td>
26
+ <td class="text-center px-4 py-2">{{ filterMessageStatus(item.status) }}</td>
27
+ <td class="text-center px-4 py-2" [style.color]="'var(--text-muted)'">{{ item.created | date: 'medium' }}</td>
28
+ <td class="text-center px-4 py-2">
29
+ <button class="btn btn-xs btn-ghost" (click)="onDeleteLog(item.id)" title="Delete">
30
+ <span class="material-symbols-outlined icon-xs">delete</span>
31
+ </button>
32
+ </td>
33
+ </tr>
34
+ }
35
+ </tbody>
36
+ </table>
37
+ } @else {
38
+ <div class="px-4 py-6 text-center text-xs" [style.color]="'var(--text-muted)'">No log entries.</div>
39
+ }
40
+ </div>
41
+ </div>
@@ -0,0 +1,43 @@
1
+ import { Component, inject, signal, OnInit } from '@angular/core';
2
+ import { DatePipe } from '@angular/common';
3
+ import { MessageService } from '../../core/services';
4
+ import type { Logger } from '@main/database/entity/Logger.schema';
5
+
6
+ @Component({
7
+ selector: 'app-settings-logs',
8
+ standalone: true,
9
+ imports: [DatePipe],
10
+ templateUrl: './logs.component.html',
11
+ })
12
+ export class SettingsLogsComponent implements OnInit {
13
+ private readonly message = inject(MessageService);
14
+
15
+ readonly logs = signal<Logger[]>([]);
16
+
17
+ async ngOnInit() {
18
+ await this.loadLogs();
19
+ }
20
+
21
+ async loadLogs() {
22
+ const result = await this.message.loggerFind({ order: { id: 'DESC' } });
23
+ this.logs.set(result);
24
+ }
25
+
26
+ filterMessageType(type: number): string {
27
+ return type === 1 ? 'System Action' : 'User Action';
28
+ }
29
+
30
+ filterMessageStatus(status: number): string {
31
+ return status === 1 ? 'Error' : 'Success';
32
+ }
33
+
34
+ async onDeleteLog(id: number) {
35
+ await this.message.loggerDelete(id);
36
+ await this.loadLogs();
37
+ }
38
+
39
+ async onTruncateLogs() {
40
+ await this.message.loggerTruncate();
41
+ await this.loadLogs();
42
+ }
43
+ }
@@ -0,0 +1,40 @@
1
+ <div class="card">
2
+ <div class="card-header">
3
+ <div class="card-title"><h3>News API</h3></div>
4
+ <div class="card-tools">
5
+ @if (newsApiKey()) {
6
+ <button class="btn btn-sm btn-default" (click)="onFetchNews()" [disabled]="fetchStatus() === 'fetching'">
7
+ {{ fetchStatus() === 'fetching' ? 'Fetching...' : 'Fetch Articles' }}
8
+ </button>
9
+ }
10
+ </div>
11
+ </div>
12
+ <div class="card-body">
13
+ <div>
14
+ <label class="form-label" for="apiKey">API Key</label>
15
+ <input
16
+ type="text"
17
+ id="apiKey"
18
+ class="form-input w-full"
19
+ [ngModel]="newsApiKey()"
20
+ (ngModelChange)="newsApiKey.set($event)"
21
+ name="apiKey"
22
+ placeholder="Enter your newsapi.org key"
23
+ />
24
+ <p class="text-xs mt-1" [style.color]="'var(--text-muted)'">Visit newsapi.org to obtain your free key.</p>
25
+ </div>
26
+ </div>
27
+ <div class="card-footer">
28
+ <div>
29
+ @if (saveStatus() === 'saved') {
30
+ <span class="text-xs" [style.color]="'var(--text-muted)'">API key saved.</span>
31
+ }
32
+ @if (fetchMessage()) {
33
+ <span class="text-xs" [style.color]="fetchStatus() === 'error' ? '#dc2626' : 'var(--text-muted)'">{{ fetchMessage() }}</span>
34
+ }
35
+ </div>
36
+ <div class="card-tools">
37
+ <button class="btn btn-sm btn-theme" (click)="onSaveNewsApiKey()">Save</button>
38
+ </div>
39
+ </div>
40
+ </div>
@@ -0,0 +1,57 @@
1
+ import { Component, inject, signal, OnInit } from '@angular/core';
2
+ import { FormsModule } from '@angular/forms';
3
+ import { MessageService, NewsService } from '../../core/services';
4
+ import { StorageType } from '@main/enums';
5
+ import type { NewsType } from '@main/types';
6
+
7
+ @Component({
8
+ selector: 'app-settings-news-api',
9
+ standalone: true,
10
+ imports: [FormsModule],
11
+ templateUrl: './news-api.component.html',
12
+ })
13
+ export class SettingsNewsApiComponent implements OnInit {
14
+ private readonly message = inject(MessageService);
15
+ private readonly news = inject(NewsService);
16
+
17
+ readonly newsApiKey = signal('');
18
+ readonly saveStatus = signal<'idle' | 'saved'>('idle');
19
+ readonly fetchStatus = signal<'idle' | 'fetching' | 'done' | 'error'>('idle');
20
+ readonly fetchMessage = signal('');
21
+
22
+ async ngOnInit() {
23
+ const config = (await this.message.get(StorageType.News, null)) as NewsType | null;
24
+ if (config?.apiKey) {
25
+ this.newsApiKey.set(config.apiKey);
26
+ }
27
+ }
28
+
29
+ async onSaveNewsApiKey() {
30
+ const apiKey = this.newsApiKey();
31
+ if (!apiKey) return;
32
+ await this.message.set(StorageType.News, { apiKey });
33
+ this.saveStatus.set('saved');
34
+ await this.news.refresh();
35
+ setTimeout(() => this.saveStatus.set('idle'), 2000);
36
+ }
37
+
38
+ async onFetchNews() {
39
+ this.fetchStatus.set('fetching');
40
+ this.fetchMessage.set('');
41
+ try {
42
+ const endpoint = `https://newsapi.org/v2/top-headlines?country=us&apiKey=${this.newsApiKey()}`;
43
+ const result = await this.message.fetchLatestNews({ endpoint });
44
+ const count = result?.articles?.length ?? 0;
45
+ this.fetchMessage.set(`Fetched ${count} article${count !== 1 ? 's' : ''}.`);
46
+ this.fetchStatus.set('done');
47
+ await this.news.refresh();
48
+ } catch {
49
+ this.fetchMessage.set('Failed to fetch articles.');
50
+ this.fetchStatus.set('error');
51
+ }
52
+ setTimeout(() => {
53
+ this.fetchStatus.set('idle');
54
+ this.fetchMessage.set('');
55
+ }, 3000);
56
+ }
57
+ }
@@ -0,0 +1,7 @@
1
+ <div class="mx-auto max-w-2xl space-y-6">
2
+ <app-settings-theme />
3
+ <app-settings-ai-keys />
4
+ <app-settings-news-api />
5
+ <app-settings-quick-actions />
6
+ <app-settings-danger-zone />
7
+ </div>
@@ -0,0 +1,20 @@
1
+ import { Component } from '@angular/core';
2
+ import { SettingsThemeComponent } from '../../theme/theme.component';
3
+ import { SettingsAiKeysComponent } from '../../ai-keys/ai-keys.component';
4
+ import { SettingsNewsApiComponent } from '../../news-api/news-api.component';
5
+ import { SettingsQuickActionsComponent } from '../../quick-actions/quick-actions.component';
6
+ import { SettingsDangerZoneComponent } from '../../danger-zone/danger-zone.component';
7
+
8
+ @Component({
9
+ selector: 'app-settings-general-page',
10
+ standalone: true,
11
+ imports: [
12
+ SettingsThemeComponent,
13
+ SettingsAiKeysComponent,
14
+ SettingsNewsApiComponent,
15
+ SettingsQuickActionsComponent,
16
+ SettingsDangerZoneComponent,
17
+ ],
18
+ templateUrl: './general.component.html',
19
+ })
20
+ export class SettingsGeneralPageComponent {}
@@ -0,0 +1 @@
1
+ <app-settings-logs />
@@ -0,0 +1,10 @@
1
+ import { Component } from '@angular/core';
2
+ import { SettingsLogsComponent } from '../../logs/logs.component';
3
+
4
+ @Component({
5
+ selector: 'app-settings-logs-page',
6
+ standalone: true,
7
+ imports: [SettingsLogsComponent],
8
+ templateUrl: './logs.component.html',
9
+ })
10
+ export class SettingsLogsPageComponent {}
@@ -0,0 +1 @@
1
+ <app-settings-system-info />
@@ -0,0 +1,10 @@
1
+ import { Component } from '@angular/core';
2
+ import { SettingsSystemInfoComponent } from '../../system-info/system-info.component';
3
+
4
+ @Component({
5
+ selector: 'app-settings-system-page',
6
+ standalone: true,
7
+ imports: [SettingsSystemInfoComponent],
8
+ templateUrl: './system.component.html',
9
+ })
10
+ export class SettingsSystemPageComponent {}
@@ -0,0 +1,49 @@
1
+ <div class="card">
2
+ <div class="card-header">
3
+ <div class="card-title"><h3>Quick Actions</h3></div>
4
+ <div class="card-tools">
5
+ @if (syncing()) {
6
+ <span class="text-xs font-medium" [style.color]="'var(--text-muted)'">Syncing...</span>
7
+ }
8
+ </div>
9
+ </div>
10
+ <div class="card-body space-y-4">
11
+ <div class="flex items-center justify-between">
12
+ <div>
13
+ <p class="text-xs font-semibold" [style.color]="'var(--text-primary)'">Reset favorited fonts</p>
14
+ <p class="text-xs" [style.color]="'var(--text-muted)'">Resets fonts that have been favorited.</p>
15
+ </div>
16
+ <button class="btn btn-sm btn-default" (click)="onResetFavorites()">Run</button>
17
+ </div>
18
+
19
+ <div class="flex items-center justify-between">
20
+ <div>
21
+ <p class="text-xs font-semibold" [style.color]="'var(--text-primary)'">Synchronize system fonts</p>
22
+ <p class="text-xs" [style.color]="'var(--text-muted)'">Imports fonts from system fonts folder.</p>
23
+ </div>
24
+ <button class="btn btn-sm btn-default" (click)="onSyncSystemFonts()" [disabled]="syncing()">
25
+ @if (syncing()) {
26
+ <app-spinner [animating]="true" />
27
+ } @else {
28
+ Run
29
+ }
30
+ </button>
31
+ </div>
32
+
33
+ <div class="flex items-center justify-between">
34
+ <div>
35
+ <p class="text-xs font-semibold" [style.color]="'var(--text-primary)'">Restart application</p>
36
+ <p class="text-xs" [style.color]="'var(--text-muted)'">Restarts the application.</p>
37
+ </div>
38
+ <button class="btn btn-sm btn-default" (click)="onRestartApp()">Run</button>
39
+ </div>
40
+
41
+ <div class="flex items-center justify-between">
42
+ <div>
43
+ <p class="text-xs font-semibold" [style.color]="'var(--text-primary)'">Exit application</p>
44
+ <p class="text-xs" [style.color]="'var(--text-muted)'">Exits the application.</p>
45
+ </div>
46
+ <button class="btn btn-sm btn-default" (click)="onExitApp()">Run</button>
47
+ </div>
48
+ </div>
49
+ </div>
@@ -0,0 +1,40 @@
1
+ import { Component, inject, signal } from '@angular/core';
2
+ import { SpinnerComponent } from '../../shared/components/spinner/spinner.component';
3
+ import { DatabaseService, MessageService } from '../../core/services';
4
+
5
+ @Component({
6
+ selector: 'app-settings-quick-actions',
7
+ standalone: true,
8
+ imports: [SpinnerComponent],
9
+ templateUrl: './quick-actions.component.html',
10
+ })
11
+ export class SettingsQuickActionsComponent {
12
+ private readonly database = inject(DatabaseService);
13
+ private readonly message = inject(MessageService);
14
+
15
+ readonly syncing = signal(false);
16
+
17
+ async onResetFavorites() {
18
+ await this.database.resetFavorites();
19
+ await this.database.fetchSystemStats();
20
+ }
21
+
22
+ async onSyncSystemFonts() {
23
+ this.syncing.set(true);
24
+ try {
25
+ await this.database.syncSystemFonts();
26
+ } finally {
27
+ this.syncing.set(false);
28
+ }
29
+ }
30
+
31
+ onRestartApp() {
32
+ this.message.beep();
33
+ this.message.reloadWindow();
34
+ }
35
+
36
+ onExitApp() {
37
+ this.message.beep();
38
+ this.message.quitApplication();
39
+ }
40
+ }
@@ -0,0 +1,47 @@
1
+ <div class="grid h-screen grid-rows-[56px_1fr_32px]" [style.background-color]="'var(--surface-0)'">
2
+ <!-- Header -->
3
+ <div
4
+ class="flex items-center justify-between px-4"
5
+ [style.background-color]="'var(--surface-2)'"
6
+ [style.border-bottom]="'1px solid var(--border-subtle)'"
7
+ >
8
+ <h1 class="text-sm font-bold" [style.color]="'var(--text-primary)'">Settings</h1>
9
+ <a routerLink="/home" class="btn btn-sm btn-default">Back</a>
10
+ </div>
11
+
12
+ <!-- Body -->
13
+ <div class="grid overflow-hidden" style="grid-template-columns: 200px 1fr">
14
+ <!-- Sidebar -->
15
+ <nav
16
+ class="overflow-auto py-4 px-3"
17
+ [style.background-color]="'var(--surface-2)'"
18
+ [style.border-right]="'1px solid var(--border-subtle)'"
19
+ >
20
+ <ul class="space-y-1">
21
+ <li>
22
+ <a routerLink="general" routerLinkActive="active" class="settings-nav-link">General</a>
23
+ </li>
24
+ <li>
25
+ <a routerLink="logs" routerLinkActive="active" class="settings-nav-link">Logs</a>
26
+ </li>
27
+ <li>
28
+ <a routerLink="system" routerLinkActive="active" class="settings-nav-link">System</a>
29
+ </li>
30
+ </ul>
31
+ </nav>
32
+
33
+ <!-- Content -->
34
+ <div class="overflow-auto" [style.background-color]="'var(--surface-1)'">
35
+ <div class="p-6">
36
+ <router-outlet />
37
+ </div>
38
+ </div>
39
+ </div>
40
+
41
+ <!-- Footer -->
42
+ <div
43
+ class="flex items-center px-4"
44
+ [style.background-color]="'var(--surface-2)'"
45
+ [style.border-top]="'1px solid var(--border-subtle)'"
46
+ ></div>
47
+ </div>
@@ -0,0 +1,10 @@
1
+ import { Component } from '@angular/core';
2
+ import { RouterLink, RouterLinkActive, RouterOutlet } from '@angular/router';
3
+
4
+ @Component({
5
+ selector: 'app-settings',
6
+ templateUrl: './settings.component.html',
7
+ standalone: true,
8
+ imports: [RouterOutlet, RouterLink, RouterLinkActive],
9
+ })
10
+ export class SettingsComponent {}
@@ -0,0 +1,21 @@
1
+ <div class="card">
2
+ <div class="card-header">
3
+ <div class="card-title"><h3>System Information</h3></div>
4
+ </div>
5
+ <div class="card-body p-0">
6
+ @if (systemSettings().length) {
7
+ <table class="w-full text-xs" [style.color]="'var(--text-primary)'">
8
+ <tbody>
9
+ @for (item of systemSettings(); track item.key) {
10
+ <tr [style.border-bottom]="'1px solid var(--border-subtle)'">
11
+ <td class="px-4 py-2 font-semibold w-1/3" [style.color]="'var(--text-secondary)'">{{ item.key }}</td>
12
+ <td class="px-4 py-2" [style.color]="'var(--text-muted)'">{{ item.value }}</td>
13
+ </tr>
14
+ }
15
+ </tbody>
16
+ </table>
17
+ } @else {
18
+ <div class="px-4 py-6 text-center text-xs" [style.color]="'var(--text-muted)'">Loading system information...</div>
19
+ }
20
+ </div>
21
+ </div>