From 79b72b3624fdb5b6dd2e8e0bc12e64d73cb6698c Mon Sep 17 00:00:00 2001 From: Matthew Maxwell Date: Sun, 15 Mar 2026 01:25:38 -0500 Subject: [PATCH] Restructure into monorepo file/folder layout --- .gitignore | 4 + .prettierrc | 2 +- CHANGELOG.md | 4 + {src => apps/desktop/src}/app.html | 0 {src => apps/desktop/src}/hooks.client.ts | 0 .../lib/components/common/AlbumArt.svelte | 5 +- .../components/common/AlbumArtModal.svelte | 2 +- .../lib/components/common/Breadcrumbs.svelte | 2 +- .../src}/lib/components/common/Button.svelte | 0 .../lib/components/common/Checkbox.svelte | 0 .../lib/components/common/ConfirmModal.svelte | 2 +- .../lib/components/common/ContextMenu.svelte | 4 +- .../common/ContextMenuOrchestrator.svelte | 4 +- .../lib/components/common/CrashScreen.svelte | 4 +- .../lib/components/common/DragPreview.svelte | 4 +- .../common/DuplicateTrackModal.svelte | 4 +- .../src}/lib/components/common/Icon.svelte | 0 .../lib/components/common/IconButton.svelte | 0 .../src}/lib/components/common/Input.svelte | 0 .../lib/components/common/InputModal.svelte | 2 +- .../src}/lib/components/common/Modal.svelte | 0 .../common/ModalOrchestrator.svelte | 10 +-- .../common/MoveConflictModal.svelte | 4 +- .../lib/components/common/ResizeHandle.svelte | 0 .../src}/lib/components/common/Select.svelte | 0 .../src}/lib/components/common/Slider.svelte | 0 .../src}/lib/components/common/Spinner.svelte | 0 .../lib/components/common/SplashScreen.svelte | 0 .../components/common/StepIndicator.svelte | 0 .../src}/lib/components/common/Text.svelte | 0 .../src}/lib/components/common/Toast.svelte | 2 +- .../components/common/ToastContainer.svelte | 2 +- .../src}/lib/components/common/Tooltip.svelte | 0 .../lib/components/common/UpdateModal.svelte | 2 +- .../src}/lib/components/common/index.ts | 0 .../devices/DeviceContextMenu.svelte | 4 +- .../components/devices/DeviceInfoModal.svelte | 6 +- .../lib/components/devices/DeviceItem.svelte | 6 +- .../lib/components/devices/DeviceList.svelte | 4 +- .../devices/DeviceStatusIndicator.svelte | 2 +- .../devices/ReformatDeviceModal.svelte | 4 +- .../src}/lib/components/devices/index.ts | 0 .../discovery/AddReleaseModal.svelte | 8 +- .../discovery/BulkImportView.svelte | 6 +- .../discovery/DiscoveryContextMenu.svelte | 6 +- .../discovery/DiscoveryEditor.svelte | 10 +-- .../components/discovery/DiscoveryList.svelte | 8 +- .../discovery/DiscoveryListHeader.svelte | 4 +- .../components/discovery/DiscoveryRow.svelte | 12 +-- .../components/discovery/DiscoveryView.svelte | 4 +- .../discovery/MergeReleasesModal.svelte | 4 +- .../discovery/PurchaseReleaseModal.svelte | 10 +-- .../src}/lib/components/discovery/index.ts | 0 .../components/editor/EditorArtwork.svelte | 6 +- .../components/editor/EditorDateField.svelte | 6 +- .../lib/components/editor/EditorField.svelte | 2 +- .../components/editor/EditorTextArea.svelte | 2 +- .../lib/components/editor/TrackEditor.svelte | 12 +-- .../src}/lib/components/editor/index.ts | 0 .../export/ExportFailureModal.svelte | 6 +- .../lib/components/export/ExportModal.svelte | 8 +- .../components/export/QuickExportModal.svelte | 6 +- .../src}/lib/components/export/index.ts | 0 .../layout/OrchestratorLayer.svelte | 16 ++-- .../lib/components/layout/RightSidebar.svelte | 0 .../src}/lib/components/layout/Sidebar.svelte | 6 +- .../src}/lib/components/layout/Toolbar.svelte | 2 +- .../src}/lib/components/layout/index.ts | 0 .../components/library/FilterDropdown.svelte | 4 +- .../lib/components/library/LibraryView.svelte | 4 +- .../library/RelocateTrackModal.svelte | 6 +- .../lib/components/library/SearchBar.svelte | 2 +- .../components/library/TrackColorCell.svelte | 4 +- .../library/TrackContextMenu.svelte | 6 +- .../lib/components/library/TrackList.svelte | 8 +- .../components/library/TrackListHeader.svelte | 6 +- .../lib/components/library/TrackRow.svelte | 14 ++- .../src}/lib/components/library/index.ts | 0 .../components/onboarding/AboutDialog.svelte | 2 +- .../onboarding/AppearanceStep.svelte | 6 +- .../components/onboarding/LanguageStep.svelte | 6 +- .../onboarding/OnboardingWizard.svelte | 2 +- .../components/onboarding/ReadyStep.svelte | 2 +- .../components/onboarding/WelcomeStep.svelte | 2 +- .../src}/lib/components/onboarding/index.ts | 0 .../components/player/PlaybackControls.svelte | 2 +- .../src}/lib/components/player/Player.svelte | 0 .../src}/lib/components/player/SeekBar.svelte | 2 +- .../lib/components/player/TempoControl.svelte | 2 +- .../lib/components/player/TrackInfo.svelte | 6 +- .../components/player/VolumeControl.svelte | 2 +- .../src}/lib/components/player/index.ts | 0 .../components/playlists/FolderCard.svelte | 6 +- .../components/playlists/FolderView.svelte | 6 +- .../playlists/PlaylistContextMenu.svelte | 4 +- .../components/playlists/PlaylistItem.svelte | 4 +- .../components/playlists/PlaylistTree.svelte | 8 +- .../components/playlists/PlaylistView.svelte | 4 +- .../playlists/SelectablePlaylistTree.svelte | 2 +- .../playlists/SmartPlaylistModal.svelte | 8 +- .../src}/lib/components/playlists/index.ts | 0 .../components/settings/SettingsModal.svelte | 6 +- .../src}/lib/components/settings/index.ts | 0 .../components/settings/tabs/AboutTab.svelte | 2 +- .../settings/tabs/AppearanceTab.svelte | 6 +- .../settings/tabs/DiagnosticsTab.svelte | 10 +-- .../settings/tabs/DiscoveryTab.svelte | 8 +- .../settings/tabs/GeneralTab.svelte | 14 +-- .../settings/tabs/LibraryTab.svelte | 6 +- .../components/settings/tabs/SoundTab.svelte | 4 +- .../lib/components/settings/tabs/index.ts | 0 .../src}/lib/components/tags/TagChip.svelte | 2 +- .../lib/components/tags/TagContextMenu.svelte | 6 +- .../lib/components/tags/TagInputModal.svelte | 2 +- .../src}/lib/components/tags/TagList.svelte | 6 +- .../tags/TagsSidebarContextMenu.svelte | 4 +- .../desktop/src}/lib/components/tags/index.ts | 0 .../lib/components/wizard/WizardTour.svelte | 2 +- .../src}/lib/components/wizard/index.ts | 0 .../src}/lib/controllers/deviceController.ts | 8 +- .../src}/lib/controllers/exportController.ts | 10 +-- .../desktop/src}/lib/controllers/index.ts | 0 .../lib/controllers/playlistController.ts | 14 +-- .../src}/lib/controllers/tagController.ts | 8 +- .../src}/lib/controllers/trackController.ts | 16 ++-- {src => apps/desktop/src}/lib/hooks/index.ts | 0 .../src}/lib/hooks/useAppInitialization.ts | 16 ++-- .../desktop/src}/lib/hooks/useAppSetup.ts | 14 +-- .../src}/lib/hooks/useDragDropCoordination.ts | 6 +- .../src}/lib/hooks/useGlobalErrorHandler.ts | 2 +- .../src}/lib/hooks/useKeyboardShortcuts.ts | 2 +- .../desktop/src}/lib/hooks/useMediaKeys.ts | 0 .../desktop/src}/lib/hooks/useMenuActions.ts | 6 +- apps/desktop/src/lib/hooks/useStoreHooks.ts | 50 +++++++++++ .../desktop/src}/lib/stores/analysis.ts | 4 +- {src => apps/desktop/src}/lib/stores/app.ts | 4 +- .../desktop/src}/lib/stores/backup.ts | 2 +- {src => apps/desktop/src}/lib/stores/crash.ts | 0 .../desktop/src}/lib/stores/devices.ts | 6 +- .../desktop/src}/lib/stores/diagnostics.ts | 4 +- {src => apps/desktop/src}/lib/stores/drag.ts | 0 .../desktop/src}/lib/stores/export.ts | 2 +- {src => apps/desktop/src}/lib/stores/index.ts | 86 ++++++++++++++----- .../desktop/src}/lib/stores/library.ts | 12 +-- .../desktop/src}/lib/stores/locate.ts | 0 .../desktop/src}/lib/stores/missingTracks.ts | 2 +- .../desktop/src}/lib/stores/pageActions.ts | 2 +- .../desktop/src}/lib/stores/splash.ts | 0 {src => apps/desktop/src}/lib/stores/sync.ts | 6 +- .../desktop/src}/lib/stores/updater.ts | 6 +- .../desktop/src}/lib/transitions/index.ts | 0 .../desktop/src}/routes/+error.svelte | 0 .../desktop/src}/routes/+layout.svelte | 12 +-- {src => apps/desktop/src}/routes/+layout.ts | 0 {src => apps/desktop/src}/routes/+page.svelte | 20 ++--- {src => apps/desktop/src}/style.css | 0 .../desktop/static}/crate-logo.svg | 0 .../desktop/svelte.config.js | 4 + tsconfig.json => apps/desktop/tsconfig.json | 0 vite.config.ts => apps/desktop/vite.config.ts | 2 +- apps/mobile/src/app.html | 12 +++ apps/mobile/src/routes/+layout.ts | 2 + apps/mobile/src/routes/+page.svelte | 11 +++ apps/mobile/svelte.config.js | 18 ++++ apps/mobile/tsconfig.json | 14 +++ apps/mobile/vite.config.ts | 7 ++ eslint.config.js | 2 - package.json | 10 +-- {src/lib => shared}/api/analysis.ts | 2 +- {src/lib => shared}/api/app.ts | 0 {src/lib => shared}/api/backup.ts | 0 {src/lib => shared}/api/devices.ts | 2 +- {src/lib => shared}/api/diagnostics.ts | 2 +- {src/lib => shared}/api/discovery.ts | 2 +- {src/lib => shared}/api/export.ts | 2 +- {src/lib => shared}/api/index.ts | 0 {src/lib => shared}/api/library.ts | 2 +- {src/lib => shared}/api/mediaControls.ts | 0 {src/lib => shared}/api/menu.ts | 0 {src/lib => shared}/api/player.ts | 2 +- {src/lib => shared}/api/playlists.ts | 2 +- {src/lib => shared}/api/settings.ts | 2 +- {src/lib => shared}/api/sync.ts | 2 +- {src/lib => shared}/api/tags.ts | 2 +- {src/lib => shared}/api/updater.ts | 0 {src/lib => shared}/i18n/index.ts | 0 {src/lib => shared}/i18n/locales/de.json | 0 {src/lib => shared}/i18n/locales/en.json | 0 {src/lib => shared}/i18n/locales/es.json | 0 {src/lib => shared}/i18n/locales/fr.json | 0 {src/lib => shared}/i18n/locales/it.json | 0 {src/lib => shared}/i18n/locales/ja.json | 0 {src/lib => shared}/i18n/locales/ko.json | 0 {src/lib => shared}/i18n/locales/nl.json | 0 {src/lib => shared}/i18n/locales/pl.json | 0 {src/lib => shared}/i18n/locales/pt.json | 0 {src/lib => shared}/i18n/locales/ro.json | 0 {src/lib => shared}/i18n/locales/sv.json | 0 {src/lib => shared}/i18n/locales/tr.json | 0 {src/lib => shared}/i18n/locales/uk.json | 0 {src/lib => shared}/i18n/locales/zh.json | 0 {src/lib => shared}/services/previewPlayer.ts | 0 {src/lib => shared}/stores/discovery.ts | 6 +- .../stores/discoveryPlaylist.ts | 2 +- .../lib => shared}/stores/expandedReleases.ts | 2 +- shared/stores/index.ts | 84 ++++++++++++++++++ {src/lib => shared}/stores/player.ts | 29 +++++-- {src/lib => shared}/stores/playlists.ts | 30 ++++--- {src/lib => shared}/stores/settings.ts | 56 ++++++------ {src/lib => shared}/stores/tags.ts | 4 +- {src/lib => shared}/stores/toast.ts | 2 +- {src/lib => shared}/stores/ui.ts | 4 +- {src/lib => shared}/types/index.ts | 0 {src/lib => shared}/utils/artwork.ts | 7 +- {src/lib => shared}/utils/bulkEdit.ts | 2 +- {src/lib => shared}/utils/dom.ts | 2 +- {src/lib => shared}/utils/drag.ts | 0 {src/lib => shared}/utils/format.ts | 0 {src/lib => shared}/utils/index.ts | 0 {src/lib => shared}/utils/playlist.ts | 2 +- {src/lib => shared}/utils/position.ts | 0 {src/lib => shared}/utils/selection.ts | 0 {src/lib => shared}/utils/smartRules.ts | 2 +- {src/lib => shared}/utils/sorting.ts | 4 +- {src/lib => shared}/utils/storage.ts | 0 {src/lib => shared}/utils/tagComputation.ts | 2 +- {src/lib => shared}/utils/transitions.ts | 0 .../utils/virtualizer.svelte.ts | 1 - src-tauri/tauri.conf.json | 2 +- 229 files changed, 688 insertions(+), 420 deletions(-) rename {src => apps/desktop/src}/app.html (100%) rename {src => apps/desktop/src}/hooks.client.ts (100%) rename {src => apps/desktop/src}/lib/components/common/AlbumArt.svelte (91%) rename {src => apps/desktop/src}/lib/components/common/AlbumArtModal.svelte (94%) rename {src => apps/desktop/src}/lib/components/common/Breadcrumbs.svelte (96%) rename {src => apps/desktop/src}/lib/components/common/Button.svelte (100%) rename {src => apps/desktop/src}/lib/components/common/Checkbox.svelte (100%) rename {src => apps/desktop/src}/lib/components/common/ConfirmModal.svelte (97%) rename {src => apps/desktop/src}/lib/components/common/ContextMenu.svelte (98%) rename {src => apps/desktop/src}/lib/components/common/ContextMenuOrchestrator.svelte (99%) rename {src => apps/desktop/src}/lib/components/common/CrashScreen.svelte (96%) rename {src => apps/desktop/src}/lib/components/common/DragPreview.svelte (98%) rename {src => apps/desktop/src}/lib/components/common/DuplicateTrackModal.svelte (98%) rename {src => apps/desktop/src}/lib/components/common/Icon.svelte (100%) rename {src => apps/desktop/src}/lib/components/common/IconButton.svelte (100%) rename {src => apps/desktop/src}/lib/components/common/Input.svelte (100%) rename {src => apps/desktop/src}/lib/components/common/InputModal.svelte (96%) rename {src => apps/desktop/src}/lib/components/common/Modal.svelte (100%) rename {src => apps/desktop/src}/lib/components/common/ModalOrchestrator.svelte (99%) rename {src => apps/desktop/src}/lib/components/common/MoveConflictModal.svelte (98%) rename {src => apps/desktop/src}/lib/components/common/ResizeHandle.svelte (100%) rename {src => apps/desktop/src}/lib/components/common/Select.svelte (100%) rename {src => apps/desktop/src}/lib/components/common/Slider.svelte (100%) rename {src => apps/desktop/src}/lib/components/common/Spinner.svelte (100%) rename {src => apps/desktop/src}/lib/components/common/SplashScreen.svelte (100%) rename {src => apps/desktop/src}/lib/components/common/StepIndicator.svelte (100%) rename {src => apps/desktop/src}/lib/components/common/Text.svelte (100%) rename {src => apps/desktop/src}/lib/components/common/Toast.svelte (95%) rename {src => apps/desktop/src}/lib/components/common/ToastContainer.svelte (82%) rename {src => apps/desktop/src}/lib/components/common/Tooltip.svelte (100%) rename {src => apps/desktop/src}/lib/components/common/UpdateModal.svelte (98%) rename {src => apps/desktop/src}/lib/components/common/index.ts (100%) rename {src => apps/desktop/src}/lib/components/devices/DeviceContextMenu.svelte (95%) rename {src => apps/desktop/src}/lib/components/devices/DeviceInfoModal.svelte (95%) rename {src => apps/desktop/src}/lib/components/devices/DeviceItem.svelte (98%) rename {src => apps/desktop/src}/lib/components/devices/DeviceList.svelte (94%) rename {src => apps/desktop/src}/lib/components/devices/DeviceStatusIndicator.svelte (96%) rename {src => apps/desktop/src}/lib/components/devices/ReformatDeviceModal.svelte (96%) rename {src => apps/desktop/src}/lib/components/devices/index.ts (100%) rename {src => apps/desktop/src}/lib/components/discovery/AddReleaseModal.svelte (98%) rename {src => apps/desktop/src}/lib/components/discovery/BulkImportView.svelte (98%) rename {src => apps/desktop/src}/lib/components/discovery/DiscoveryContextMenu.svelte (97%) rename {src => apps/desktop/src}/lib/components/discovery/DiscoveryEditor.svelte (97%) rename {src => apps/desktop/src}/lib/components/discovery/DiscoveryList.svelte (97%) rename {src => apps/desktop/src}/lib/components/discovery/DiscoveryListHeader.svelte (97%) rename {src => apps/desktop/src}/lib/components/discovery/DiscoveryRow.svelte (97%) rename {src => apps/desktop/src}/lib/components/discovery/DiscoveryView.svelte (98%) rename {src => apps/desktop/src}/lib/components/discovery/MergeReleasesModal.svelte (97%) rename {src => apps/desktop/src}/lib/components/discovery/PurchaseReleaseModal.svelte (97%) rename {src => apps/desktop/src}/lib/components/discovery/index.ts (100%) rename {src => apps/desktop/src}/lib/components/editor/EditorArtwork.svelte (93%) rename {src => apps/desktop/src}/lib/components/editor/EditorDateField.svelte (98%) rename {src => apps/desktop/src}/lib/components/editor/EditorField.svelte (97%) rename {src => apps/desktop/src}/lib/components/editor/EditorTextArea.svelte (96%) rename {src => apps/desktop/src}/lib/components/editor/TrackEditor.svelte (96%) rename {src => apps/desktop/src}/lib/components/editor/index.ts (100%) rename {src => apps/desktop/src}/lib/components/export/ExportFailureModal.svelte (94%) rename {src => apps/desktop/src}/lib/components/export/ExportModal.svelte (97%) rename {src => apps/desktop/src}/lib/components/export/QuickExportModal.svelte (97%) rename {src => apps/desktop/src}/lib/components/export/index.ts (100%) rename {src => apps/desktop/src}/lib/components/layout/OrchestratorLayer.svelte (97%) rename {src => apps/desktop/src}/lib/components/layout/RightSidebar.svelte (100%) rename {src => apps/desktop/src}/lib/components/layout/Sidebar.svelte (98%) rename {src => apps/desktop/src}/lib/components/layout/Toolbar.svelte (96%) rename {src => apps/desktop/src}/lib/components/layout/index.ts (100%) rename {src => apps/desktop/src}/lib/components/library/FilterDropdown.svelte (99%) rename {src => apps/desktop/src}/lib/components/library/LibraryView.svelte (98%) rename {src => apps/desktop/src}/lib/components/library/RelocateTrackModal.svelte (97%) rename {src => apps/desktop/src}/lib/components/library/SearchBar.svelte (97%) rename {src => apps/desktop/src}/lib/components/library/TrackColorCell.svelte (88%) rename {src => apps/desktop/src}/lib/components/library/TrackContextMenu.svelte (98%) rename {src => apps/desktop/src}/lib/components/library/TrackList.svelte (96%) rename {src => apps/desktop/src}/lib/components/library/TrackListHeader.svelte (93%) rename {src => apps/desktop/src}/lib/components/library/TrackRow.svelte (95%) rename {src => apps/desktop/src}/lib/components/library/index.ts (100%) rename {src => apps/desktop/src}/lib/components/onboarding/AboutDialog.svelte (96%) rename {src => apps/desktop/src}/lib/components/onboarding/AppearanceStep.svelte (95%) rename {src => apps/desktop/src}/lib/components/onboarding/LanguageStep.svelte (84%) rename {src => apps/desktop/src}/lib/components/onboarding/OnboardingWizard.svelte (98%) rename {src => apps/desktop/src}/lib/components/onboarding/ReadyStep.svelte (93%) rename {src => apps/desktop/src}/lib/components/onboarding/WelcomeStep.svelte (94%) rename {src => apps/desktop/src}/lib/components/onboarding/index.ts (100%) rename {src => apps/desktop/src}/lib/components/player/PlaybackControls.svelte (96%) rename {src => apps/desktop/src}/lib/components/player/Player.svelte (100%) rename {src => apps/desktop/src}/lib/components/player/SeekBar.svelte (97%) rename {src => apps/desktop/src}/lib/components/player/TempoControl.svelte (97%) rename {src => apps/desktop/src}/lib/components/player/TrackInfo.svelte (94%) rename {src => apps/desktop/src}/lib/components/player/VolumeControl.svelte (96%) rename {src => apps/desktop/src}/lib/components/player/index.ts (100%) rename {src => apps/desktop/src}/lib/components/playlists/FolderCard.svelte (93%) rename {src => apps/desktop/src}/lib/components/playlists/FolderView.svelte (96%) rename {src => apps/desktop/src}/lib/components/playlists/PlaylistContextMenu.svelte (98%) rename {src => apps/desktop/src}/lib/components/playlists/PlaylistItem.svelte (98%) rename {src => apps/desktop/src}/lib/components/playlists/PlaylistTree.svelte (97%) rename {src => apps/desktop/src}/lib/components/playlists/PlaylistView.svelte (99%) rename {src => apps/desktop/src}/lib/components/playlists/SelectablePlaylistTree.svelte (97%) rename {src => apps/desktop/src}/lib/components/playlists/SmartPlaylistModal.svelte (98%) rename {src => apps/desktop/src}/lib/components/playlists/index.ts (100%) rename {src => apps/desktop/src}/lib/components/settings/SettingsModal.svelte (97%) rename {src => apps/desktop/src}/lib/components/settings/index.ts (100%) rename {src => apps/desktop/src}/lib/components/settings/tabs/AboutTab.svelte (98%) rename {src => apps/desktop/src}/lib/components/settings/tabs/AppearanceTab.svelte (95%) rename {src => apps/desktop/src}/lib/components/settings/tabs/DiagnosticsTab.svelte (96%) rename {src => apps/desktop/src}/lib/components/settings/tabs/DiscoveryTab.svelte (94%) rename {src => apps/desktop/src}/lib/components/settings/tabs/GeneralTab.svelte (96%) rename {src => apps/desktop/src}/lib/components/settings/tabs/LibraryTab.svelte (98%) rename {src => apps/desktop/src}/lib/components/settings/tabs/SoundTab.svelte (96%) rename {src => apps/desktop/src}/lib/components/settings/tabs/index.ts (100%) rename {src => apps/desktop/src}/lib/components/tags/TagChip.svelte (96%) rename {src => apps/desktop/src}/lib/components/tags/TagContextMenu.svelte (95%) rename {src => apps/desktop/src}/lib/components/tags/TagInputModal.svelte (97%) rename {src => apps/desktop/src}/lib/components/tags/TagList.svelte (96%) rename {src => apps/desktop/src}/lib/components/tags/TagsSidebarContextMenu.svelte (87%) rename {src => apps/desktop/src}/lib/components/tags/index.ts (100%) rename {src => apps/desktop/src}/lib/components/wizard/WizardTour.svelte (99%) rename {src => apps/desktop/src}/lib/components/wizard/index.ts (100%) rename {src => apps/desktop/src}/lib/controllers/deviceController.ts (92%) rename {src => apps/desktop/src}/lib/controllers/exportController.ts (95%) rename {src => apps/desktop/src}/lib/controllers/index.ts (100%) rename {src => apps/desktop/src}/lib/controllers/playlistController.ts (95%) rename {src => apps/desktop/src}/lib/controllers/tagController.ts (97%) rename {src => apps/desktop/src}/lib/controllers/trackController.ts (96%) rename {src => apps/desktop/src}/lib/hooks/index.ts (100%) rename {src => apps/desktop/src}/lib/hooks/useAppInitialization.ts (91%) rename {src => apps/desktop/src}/lib/hooks/useAppSetup.ts (98%) rename {src => apps/desktop/src}/lib/hooks/useDragDropCoordination.ts (98%) rename {src => apps/desktop/src}/lib/hooks/useGlobalErrorHandler.ts (97%) rename {src => apps/desktop/src}/lib/hooks/useKeyboardShortcuts.ts (99%) rename {src => apps/desktop/src}/lib/hooks/useMediaKeys.ts (100%) rename {src => apps/desktop/src}/lib/hooks/useMenuActions.ts (96%) create mode 100644 apps/desktop/src/lib/hooks/useStoreHooks.ts rename {src => apps/desktop/src}/lib/stores/analysis.ts (98%) rename {src => apps/desktop/src}/lib/stores/app.ts (95%) rename {src => apps/desktop/src}/lib/stores/backup.ts (98%) rename {src => apps/desktop/src}/lib/stores/crash.ts (100%) rename {src => apps/desktop/src}/lib/stores/devices.ts (95%) rename {src => apps/desktop/src}/lib/stores/diagnostics.ts (97%) rename {src => apps/desktop/src}/lib/stores/drag.ts (100%) rename {src => apps/desktop/src}/lib/stores/export.ts (98%) rename {src => apps/desktop/src}/lib/stores/index.ts (60%) rename {src => apps/desktop/src}/lib/stores/library.ts (97%) rename {src => apps/desktop/src}/lib/stores/locate.ts (100%) rename {src => apps/desktop/src}/lib/stores/missingTracks.ts (98%) rename {src => apps/desktop/src}/lib/stores/pageActions.ts (95%) rename {src => apps/desktop/src}/lib/stores/splash.ts (100%) rename {src => apps/desktop/src}/lib/stores/sync.ts (97%) rename {src => apps/desktop/src}/lib/stores/updater.ts (96%) rename {src => apps/desktop/src}/lib/transitions/index.ts (100%) rename {src => apps/desktop/src}/routes/+error.svelte (100%) rename {src => apps/desktop/src}/routes/+layout.svelte (98%) rename {src => apps/desktop/src}/routes/+layout.ts (100%) rename {src => apps/desktop/src}/routes/+page.svelte (98%) rename {src => apps/desktop/src}/style.css (100%) rename {static => apps/desktop/static}/crate-logo.svg (100%) rename svelte.config.js => apps/desktop/svelte.config.js (87%) rename tsconfig.json => apps/desktop/tsconfig.json (100%) rename vite.config.ts => apps/desktop/vite.config.ts (95%) create mode 100644 apps/mobile/src/app.html create mode 100644 apps/mobile/src/routes/+layout.ts create mode 100644 apps/mobile/src/routes/+page.svelte create mode 100644 apps/mobile/svelte.config.js create mode 100644 apps/mobile/tsconfig.json create mode 100644 apps/mobile/vite.config.ts rename {src/lib => shared}/api/analysis.ts (95%) rename {src/lib => shared}/api/app.ts (100%) rename {src/lib => shared}/api/backup.ts (100%) rename {src/lib => shared}/api/devices.ts (93%) rename {src/lib => shared}/api/diagnostics.ts (98%) rename {src/lib => shared}/api/discovery.ts (99%) rename {src/lib => shared}/api/export.ts (97%) rename {src/lib => shared}/api/index.ts (100%) rename {src/lib => shared}/api/library.ts (99%) rename {src/lib => shared}/api/mediaControls.ts (100%) rename {src/lib => shared}/api/menu.ts (100%) rename {src/lib => shared}/api/player.ts (96%) rename {src/lib => shared}/api/playlists.ts (99%) rename {src/lib => shared}/api/settings.ts (92%) rename {src/lib => shared}/api/sync.ts (97%) rename {src/lib => shared}/api/tags.ts (97%) rename {src/lib => shared}/api/updater.ts (100%) rename {src/lib => shared}/i18n/index.ts (100%) rename {src/lib => shared}/i18n/locales/de.json (100%) rename {src/lib => shared}/i18n/locales/en.json (100%) rename {src/lib => shared}/i18n/locales/es.json (100%) rename {src/lib => shared}/i18n/locales/fr.json (100%) rename {src/lib => shared}/i18n/locales/it.json (100%) rename {src/lib => shared}/i18n/locales/ja.json (100%) rename {src/lib => shared}/i18n/locales/ko.json (100%) rename {src/lib => shared}/i18n/locales/nl.json (100%) rename {src/lib => shared}/i18n/locales/pl.json (100%) rename {src/lib => shared}/i18n/locales/pt.json (100%) rename {src/lib => shared}/i18n/locales/ro.json (100%) rename {src/lib => shared}/i18n/locales/sv.json (100%) rename {src/lib => shared}/i18n/locales/tr.json (100%) rename {src/lib => shared}/i18n/locales/uk.json (100%) rename {src/lib => shared}/i18n/locales/zh.json (100%) rename {src/lib => shared}/services/previewPlayer.ts (100%) rename {src/lib => shared}/stores/discovery.ts (99%) rename {src/lib => shared}/stores/discoveryPlaylist.ts (98%) rename {src/lib => shared}/stores/expandedReleases.ts (95%) create mode 100644 shared/stores/index.ts rename {src/lib => shared}/stores/player.ts (97%) rename {src/lib => shared}/stores/playlists.ts (96%) rename {src/lib => shared}/stores/settings.ts (94%) rename {src/lib => shared}/stores/tags.ts (99%) rename {src/lib => shared}/stores/toast.ts (98%) rename {src/lib => shared}/stores/ui.ts (99%) rename {src/lib => shared}/types/index.ts (100%) rename {src/lib => shared}/utils/artwork.ts (79%) rename {src/lib => shared}/utils/bulkEdit.ts (98%) rename {src/lib => shared}/utils/dom.ts (94%) rename {src/lib => shared}/utils/drag.ts (100%) rename {src/lib => shared}/utils/format.ts (100%) rename {src/lib => shared}/utils/index.ts (100%) rename {src/lib => shared}/utils/playlist.ts (95%) rename {src/lib => shared}/utils/position.ts (100%) rename {src/lib => shared}/utils/selection.ts (100%) rename {src/lib => shared}/utils/smartRules.ts (99%) rename {src/lib => shared}/utils/sorting.ts (96%) rename {src/lib => shared}/utils/storage.ts (100%) rename {src/lib => shared}/utils/tagComputation.ts (98%) rename {src/lib => shared}/utils/transitions.ts (100%) rename {src/lib => shared}/utils/virtualizer.svelte.ts (99%) diff --git a/.gitignore b/.gitignore index 76005eeb..7a277761 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,10 @@ node_modules /build /.svelte-kit +apps/desktop/.svelte-kit/ +apps/desktop/build/ +apps/mobile/.svelte-kit/ +apps/mobile/build/ /package .env .env.* diff --git a/.prettierrc b/.prettierrc index 25d3f770..3a9ed947 100644 --- a/.prettierrc +++ b/.prettierrc @@ -16,5 +16,5 @@ } } ], - "tailwindStylesheet": "./src/style.css" + "tailwindStylesheet": "./apps/desktop/src/style.css" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 9dec8602..ed5af48a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] +### Changed + +- Restructured codebase into monorepo layout with shared code (`shared/`) and platform-specific frontends (`apps/desktop/`, `apps/mobile/`) + ## [0.2.8] - 2026-03-15 ### Added diff --git a/src/app.html b/apps/desktop/src/app.html similarity index 100% rename from src/app.html rename to apps/desktop/src/app.html diff --git a/src/hooks.client.ts b/apps/desktop/src/hooks.client.ts similarity index 100% rename from src/hooks.client.ts rename to apps/desktop/src/hooks.client.ts diff --git a/src/lib/components/common/AlbumArt.svelte b/apps/desktop/src/lib/components/common/AlbumArt.svelte similarity index 91% rename from src/lib/components/common/AlbumArt.svelte rename to apps/desktop/src/lib/components/common/AlbumArt.svelte index e4ddc335..4945c884 100644 --- a/src/lib/components/common/AlbumArt.svelte +++ b/apps/desktop/src/lib/components/common/AlbumArt.svelte @@ -1,5 +1,6 @@ diff --git a/src/lib/components/common/Tooltip.svelte b/apps/desktop/src/lib/components/common/Tooltip.svelte similarity index 100% rename from src/lib/components/common/Tooltip.svelte rename to apps/desktop/src/lib/components/common/Tooltip.svelte diff --git a/src/lib/components/common/UpdateModal.svelte b/apps/desktop/src/lib/components/common/UpdateModal.svelte similarity index 98% rename from src/lib/components/common/UpdateModal.svelte rename to apps/desktop/src/lib/components/common/UpdateModal.svelte index 7cb185b0..fdbd119b 100644 --- a/src/lib/components/common/UpdateModal.svelte +++ b/apps/desktop/src/lib/components/common/UpdateModal.svelte @@ -1,6 +1,6 @@
diff --git a/src/lib/components/onboarding/OnboardingWizard.svelte b/apps/desktop/src/lib/components/onboarding/OnboardingWizard.svelte similarity index 98% rename from src/lib/components/onboarding/OnboardingWizard.svelte rename to apps/desktop/src/lib/components/onboarding/OnboardingWizard.svelte index b5707367..b6cafb53 100644 --- a/src/lib/components/onboarding/OnboardingWizard.svelte +++ b/apps/desktop/src/lib/components/onboarding/OnboardingWizard.svelte @@ -2,7 +2,7 @@ import { fly, fade } from 'svelte/transition' import { cubicOut } from 'svelte/easing' import { Button, StepIndicator } from '$lib/components/common' - import { translate } from '$lib/i18n' + import { translate } from '$shared/i18n' import WelcomeStep from './WelcomeStep.svelte' import LanguageStep from './LanguageStep.svelte' import AppearanceStep from './AppearanceStep.svelte' diff --git a/src/lib/components/onboarding/ReadyStep.svelte b/apps/desktop/src/lib/components/onboarding/ReadyStep.svelte similarity index 93% rename from src/lib/components/onboarding/ReadyStep.svelte rename to apps/desktop/src/lib/components/onboarding/ReadyStep.svelte index 41ccbbcc..cd30f68d 100644 --- a/src/lib/components/onboarding/ReadyStep.svelte +++ b/apps/desktop/src/lib/components/onboarding/ReadyStep.svelte @@ -1,7 +1,7 @@
diff --git a/src/lib/components/onboarding/WelcomeStep.svelte b/apps/desktop/src/lib/components/onboarding/WelcomeStep.svelte similarity index 94% rename from src/lib/components/onboarding/WelcomeStep.svelte rename to apps/desktop/src/lib/components/onboarding/WelcomeStep.svelte index 40cebb40..c7599ec2 100644 --- a/src/lib/components/onboarding/WelcomeStep.svelte +++ b/apps/desktop/src/lib/components/onboarding/WelcomeStep.svelte @@ -1,6 +1,6 @@
diff --git a/src/lib/components/onboarding/index.ts b/apps/desktop/src/lib/components/onboarding/index.ts similarity index 100% rename from src/lib/components/onboarding/index.ts rename to apps/desktop/src/lib/components/onboarding/index.ts diff --git a/src/lib/components/player/PlaybackControls.svelte b/apps/desktop/src/lib/components/player/PlaybackControls.svelte similarity index 96% rename from src/lib/components/player/PlaybackControls.svelte rename to apps/desktop/src/lib/components/player/PlaybackControls.svelte index ffa13415..76e07d09 100644 --- a/src/lib/components/player/PlaybackControls.svelte +++ b/apps/desktop/src/lib/components/player/PlaybackControls.svelte @@ -1,6 +1,6 @@ + +
+

Crate Mobile

+

Scaffold placeholder — shared type resolution {placeholder === null ? 'works' : 'works'}.

+
diff --git a/apps/mobile/svelte.config.js b/apps/mobile/svelte.config.js new file mode 100644 index 00000000..6498264d --- /dev/null +++ b/apps/mobile/svelte.config.js @@ -0,0 +1,18 @@ +import adapter from '@sveltejs/adapter-static' +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +/** @type {import('@sveltejs/kit').Config} */ +const config = { + preprocess: vitePreprocess(), + kit: { + adapter: adapter({ + fallback: 'index.html', + }), + alias: { + $shared: '../../shared', + '$shared/*': '../../shared/*', + }, + }, +} + +export default config diff --git a/apps/mobile/tsconfig.json b/apps/mobile/tsconfig.json new file mode 100644 index 00000000..a8f10c8e --- /dev/null +++ b/apps/mobile/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "./.svelte-kit/tsconfig.json", + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "moduleResolution": "bundler" + } +} diff --git a/apps/mobile/vite.config.ts b/apps/mobile/vite.config.ts new file mode 100644 index 00000000..2270b88f --- /dev/null +++ b/apps/mobile/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import { sveltekit } from '@sveltejs/kit/vite' + +// https://vite.dev/config/ +export default defineConfig(async () => ({ + plugins: [sveltekit()], +})) diff --git a/eslint.config.js b/eslint.config.js index 071eb99e..608b343b 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -44,10 +44,8 @@ export default defineConfig( }, { files: ['**/*.svelte', '**/*.svelte.ts', '**/*.svelte.js'], - basePath: 'src', languageOptions: { parserOptions: { - projectService: true, extraFileExtensions: ['.svelte'], parser: ts.parser, }, diff --git a/package.json b/package.json index 1c73b9c2..e0a2dc93 100644 --- a/package.json +++ b/package.json @@ -5,15 +5,15 @@ "type": "module", "scripts": { "dev": "cross-env CRATE_ENV=development tauri dev --config src-tauri/tauri.dev.conf.json -- --release --features devtools", - "dev:vite": "vite dev", + "dev:vite": "cd apps/desktop && vite dev", "build": "yarn build:production", "build:production": "cross-env CRATE_ENV=production tauri build --config src-tauri/tauri.prod.conf.json", "build:staging": "cross-env CRATE_ENV=staging tauri build --config src-tauri/tauri.staging.conf.json -- --features devtools", - "build:vite": "vite build", + "build:vite": "cd apps/desktop && vite build", "check": "yarn check:cargo && yarn check:svelte", "check:cargo": "cd src-tauri/ && cargo check --release", - "check:svelte": "svelte-kit sync && svelte-check --tsconfig tsconfig.json", - "check:watch": "svelte-kit sync && svelte-check --tsconfig tsconfig.json --watch", + "check:svelte": "cd apps/desktop && svelte-kit sync && svelte-check --tsconfig tsconfig.json", + "check:watch": "cd apps/desktop && svelte-kit sync && svelte-check --tsconfig tsconfig.json --watch", "format": "yarn format:fix && yarn format:rust", "format:check": "prettier --check \"**/*.{ts,js,json,svelte,css}\"", "format:fix": "prettier --write \"**/*.{ts,js,json,svelte,css}\"", @@ -25,7 +25,7 @@ "pre-commit": "lint-staged", "prepare": "yarn prepare:husky", "prepare:husky": "husky install", - "preview": "vite preview", + "preview": "cd apps/desktop && vite preview", "tauri": "tauri", "bump": "node scripts/version.js", "changelog:prepare": "node scripts/changelog.js prepare", diff --git a/src/lib/api/analysis.ts b/shared/api/analysis.ts similarity index 95% rename from src/lib/api/analysis.ts rename to shared/api/analysis.ts index 277fed83..723c3978 100644 --- a/src/lib/api/analysis.ts +++ b/shared/api/analysis.ts @@ -1,5 +1,5 @@ import { invoke } from '@tauri-apps/api/core' -import type { Track } from '$lib/types' +import type { Track } from '../types' /** * Analyze tracks for BPM and key detection diff --git a/src/lib/api/app.ts b/shared/api/app.ts similarity index 100% rename from src/lib/api/app.ts rename to shared/api/app.ts diff --git a/src/lib/api/backup.ts b/shared/api/backup.ts similarity index 100% rename from src/lib/api/backup.ts rename to shared/api/backup.ts diff --git a/src/lib/api/devices.ts b/shared/api/devices.ts similarity index 93% rename from src/lib/api/devices.ts rename to shared/api/devices.ts index 47dd931d..187df567 100644 --- a/src/lib/api/devices.ts +++ b/shared/api/devices.ts @@ -1,5 +1,5 @@ import { invoke } from '@tauri-apps/api/core' -import type { UsbDevice } from '$lib/types' +import type { UsbDevice } from '../types' /** * Get all connected removable USB devices diff --git a/src/lib/api/diagnostics.ts b/shared/api/diagnostics.ts similarity index 98% rename from src/lib/api/diagnostics.ts rename to shared/api/diagnostics.ts index 1be84103..7b8e12ff 100644 --- a/src/lib/api/diagnostics.ts +++ b/shared/api/diagnostics.ts @@ -1,5 +1,5 @@ import { invoke } from '@tauri-apps/api/core' -import type { DiagnosticEntry, DiagnosticsReport, SystemInfo } from '$lib/types' +import type { DiagnosticEntry, DiagnosticsReport, SystemInfo } from '../types' /** * Get all diagnostic entries diff --git a/src/lib/api/discovery.ts b/shared/api/discovery.ts similarity index 99% rename from src/lib/api/discovery.ts rename to shared/api/discovery.ts index 8e4576c3..1208f574 100644 --- a/src/lib/api/discovery.ts +++ b/shared/api/discovery.ts @@ -10,7 +10,7 @@ import type { ScannedPage, ScannedRelease, BulkImportResult, -} from '$lib/types' +} from '../types' export async function createRelease(create: DiscoveryReleaseCreate): Promise { return invoke('create_discovery_release', { create }) diff --git a/src/lib/api/export.ts b/shared/api/export.ts similarity index 97% rename from src/lib/api/export.ts rename to shared/api/export.ts index f987e60f..2ceae0e1 100644 --- a/src/lib/api/export.ts +++ b/shared/api/export.ts @@ -1,5 +1,5 @@ import { invoke } from '@tauri-apps/api/core' -import type { ExportRequest, ExportResult, DeviceExport, ExportCheckpoint } from '$lib/types' +import type { ExportRequest, ExportResult, DeviceExport, ExportCheckpoint } from '../types' /** * Export playlists to a USB device diff --git a/src/lib/api/index.ts b/shared/api/index.ts similarity index 100% rename from src/lib/api/index.ts rename to shared/api/index.ts diff --git a/src/lib/api/library.ts b/shared/api/library.ts similarity index 99% rename from src/lib/api/library.ts rename to shared/api/library.ts index fb5c1989..995d66cc 100644 --- a/src/lib/api/library.ts +++ b/shared/api/library.ts @@ -8,7 +8,7 @@ import type { TrackColor, TrackFilter, TrackUpdate, -} from '$lib/types' +} from '../types' /** * Import tracks from file paths into the library diff --git a/src/lib/api/mediaControls.ts b/shared/api/mediaControls.ts similarity index 100% rename from src/lib/api/mediaControls.ts rename to shared/api/mediaControls.ts diff --git a/src/lib/api/menu.ts b/shared/api/menu.ts similarity index 100% rename from src/lib/api/menu.ts rename to shared/api/menu.ts diff --git a/src/lib/api/player.ts b/shared/api/player.ts similarity index 96% rename from src/lib/api/player.ts rename to shared/api/player.ts index 888aab96..db40adef 100644 --- a/src/lib/api/player.ts +++ b/shared/api/player.ts @@ -1,5 +1,5 @@ import { invoke } from '@tauri-apps/api/core' -import type { PlaybackState } from '$lib/types' +import type { PlaybackState } from '../types' /** * Start playing a track by ID diff --git a/src/lib/api/playlists.ts b/shared/api/playlists.ts similarity index 99% rename from src/lib/api/playlists.ts rename to shared/api/playlists.ts index d7359e0f..a4ca79a2 100644 --- a/src/lib/api/playlists.ts +++ b/shared/api/playlists.ts @@ -6,7 +6,7 @@ import type { Playlist, SmartRules, Track, -} from '$lib/types' +} from '../types' /** * Get all playlists for a given context diff --git a/src/lib/api/settings.ts b/shared/api/settings.ts similarity index 92% rename from src/lib/api/settings.ts rename to shared/api/settings.ts index 5a2d99bb..7d970e49 100644 --- a/src/lib/api/settings.ts +++ b/shared/api/settings.ts @@ -1,5 +1,5 @@ import { invoke } from '@tauri-apps/api/core' -import type { AppSettings, AudioDevice } from '$lib/types' +import type { AppSettings, AudioDevice } from '../types' /** * Get all application settings diff --git a/src/lib/api/sync.ts b/shared/api/sync.ts similarity index 97% rename from src/lib/api/sync.ts rename to shared/api/sync.ts index 22fa8c3b..a104e1c1 100644 --- a/src/lib/api/sync.ts +++ b/shared/api/sync.ts @@ -1,5 +1,5 @@ import { invoke } from '@tauri-apps/api/core' -import type { SyncResult, DeviceInfo } from '$lib/types' +import type { SyncResult, DeviceInfo } from '../types' /** * Sync playlists to a USB device (incremental sync) diff --git a/src/lib/api/tags.ts b/shared/api/tags.ts similarity index 97% rename from src/lib/api/tags.ts rename to shared/api/tags.ts index 2fec2297..b7960838 100644 --- a/src/lib/api/tags.ts +++ b/shared/api/tags.ts @@ -1,5 +1,5 @@ import { invoke } from '@tauri-apps/api/core' -import type { Tag, TagCategory } from '$lib/types' +import type { Tag, TagCategory } from '../types' /** * Get all tag categories with their tags diff --git a/src/lib/api/updater.ts b/shared/api/updater.ts similarity index 100% rename from src/lib/api/updater.ts rename to shared/api/updater.ts diff --git a/src/lib/i18n/index.ts b/shared/i18n/index.ts similarity index 100% rename from src/lib/i18n/index.ts rename to shared/i18n/index.ts diff --git a/src/lib/i18n/locales/de.json b/shared/i18n/locales/de.json similarity index 100% rename from src/lib/i18n/locales/de.json rename to shared/i18n/locales/de.json diff --git a/src/lib/i18n/locales/en.json b/shared/i18n/locales/en.json similarity index 100% rename from src/lib/i18n/locales/en.json rename to shared/i18n/locales/en.json diff --git a/src/lib/i18n/locales/es.json b/shared/i18n/locales/es.json similarity index 100% rename from src/lib/i18n/locales/es.json rename to shared/i18n/locales/es.json diff --git a/src/lib/i18n/locales/fr.json b/shared/i18n/locales/fr.json similarity index 100% rename from src/lib/i18n/locales/fr.json rename to shared/i18n/locales/fr.json diff --git a/src/lib/i18n/locales/it.json b/shared/i18n/locales/it.json similarity index 100% rename from src/lib/i18n/locales/it.json rename to shared/i18n/locales/it.json diff --git a/src/lib/i18n/locales/ja.json b/shared/i18n/locales/ja.json similarity index 100% rename from src/lib/i18n/locales/ja.json rename to shared/i18n/locales/ja.json diff --git a/src/lib/i18n/locales/ko.json b/shared/i18n/locales/ko.json similarity index 100% rename from src/lib/i18n/locales/ko.json rename to shared/i18n/locales/ko.json diff --git a/src/lib/i18n/locales/nl.json b/shared/i18n/locales/nl.json similarity index 100% rename from src/lib/i18n/locales/nl.json rename to shared/i18n/locales/nl.json diff --git a/src/lib/i18n/locales/pl.json b/shared/i18n/locales/pl.json similarity index 100% rename from src/lib/i18n/locales/pl.json rename to shared/i18n/locales/pl.json diff --git a/src/lib/i18n/locales/pt.json b/shared/i18n/locales/pt.json similarity index 100% rename from src/lib/i18n/locales/pt.json rename to shared/i18n/locales/pt.json diff --git a/src/lib/i18n/locales/ro.json b/shared/i18n/locales/ro.json similarity index 100% rename from src/lib/i18n/locales/ro.json rename to shared/i18n/locales/ro.json diff --git a/src/lib/i18n/locales/sv.json b/shared/i18n/locales/sv.json similarity index 100% rename from src/lib/i18n/locales/sv.json rename to shared/i18n/locales/sv.json diff --git a/src/lib/i18n/locales/tr.json b/shared/i18n/locales/tr.json similarity index 100% rename from src/lib/i18n/locales/tr.json rename to shared/i18n/locales/tr.json diff --git a/src/lib/i18n/locales/uk.json b/shared/i18n/locales/uk.json similarity index 100% rename from src/lib/i18n/locales/uk.json rename to shared/i18n/locales/uk.json diff --git a/src/lib/i18n/locales/zh.json b/shared/i18n/locales/zh.json similarity index 100% rename from src/lib/i18n/locales/zh.json rename to shared/i18n/locales/zh.json diff --git a/src/lib/services/previewPlayer.ts b/shared/services/previewPlayer.ts similarity index 100% rename from src/lib/services/previewPlayer.ts rename to shared/services/previewPlayer.ts diff --git a/src/lib/stores/discovery.ts b/shared/stores/discovery.ts similarity index 99% rename from src/lib/stores/discovery.ts rename to shared/stores/discovery.ts index 792f2fcb..43333aa5 100644 --- a/src/lib/stores/discovery.ts +++ b/shared/stores/discovery.ts @@ -6,13 +6,13 @@ import type { DiscoveryFilter, DiscoverySortConfig, ImportResultWithDuplicates, -} from '$lib/types' -import * as discoveryApi from '$lib/api/discovery' +} from '../types' +import * as discoveryApi from '../api/discovery' import { playerStore } from './player' import { discoveryPlaylistStore } from './discoveryPlaylist' import { uiStore } from './ui' import { toastStore } from './toast' -import { translate } from '$lib/i18n' +import { translate } from '../i18n' // ============================================================================= // State diff --git a/src/lib/stores/discoveryPlaylist.ts b/shared/stores/discoveryPlaylist.ts similarity index 98% rename from src/lib/stores/discoveryPlaylist.ts rename to shared/stores/discoveryPlaylist.ts index 48bb2322..b92e60eb 100644 --- a/src/lib/stores/discoveryPlaylist.ts +++ b/shared/stores/discoveryPlaylist.ts @@ -1,5 +1,5 @@ import { writable, derived } from 'svelte/store' -import type { DiscoveryRelease } from '$lib/types' +import type { DiscoveryRelease } from '../types' import { SvelteMap } from 'svelte/reactivity' // ============================================================================= diff --git a/src/lib/stores/expandedReleases.ts b/shared/stores/expandedReleases.ts similarity index 95% rename from src/lib/stores/expandedReleases.ts rename to shared/stores/expandedReleases.ts index eabf96b8..04280de0 100644 --- a/src/lib/stores/expandedReleases.ts +++ b/shared/stores/expandedReleases.ts @@ -1,5 +1,5 @@ import { writable } from 'svelte/store' -import { getStoredSet, setStoredSet } from '$lib/utils/storage' +import { getStoredSet, setStoredSet } from '../utils/storage' const STORAGE_KEY = 'expandedReleaseIds' diff --git a/shared/stores/index.ts b/shared/stores/index.ts new file mode 100644 index 00000000..343d4401 --- /dev/null +++ b/shared/stores/index.ts @@ -0,0 +1,84 @@ +export { + playerStore, + isPlaying, + currentTrack, + playbackPosition, + playbackDuration, + volume, + playbackProgress, + playbackSource, + playbackSpeed, + previewInfo, + previewTrackIndex, + previewLoadingReleaseId, + isMuted, +} from './player' +export type { PlayerStoreHooks } from './player' +export { tagsStore, allTags, getTagById, getCategoryById, computeTagStates } from './tags' +export { + playlistsStore, + rootPlaylists, + getPlaylistChildren, + buildPlaylistTree, + getPlaylistPath, + buildBreadcrumbItems, +} from './playlists' +export type { PlaylistTreeNode, PlaylistsStoreHooks } from './playlists' +export { + uiStore, + activeView, + selectedTrackIds, + selectedTrackCount, + hasSelection, + selectedReleaseIds, + selectedReleaseCount, + recentlyToggledMixedTags, + selectedTagIds, + tagFilterMode, + rightSidebarVisible, + rightSidebarWidth, + selectedTreeIds, + contextMenuPlaylistId, + scrollOffset, + playlistScrollOffsets, +} from './ui' +export { toastStore, toasts, hasToasts } from './toast' +export type { Toast, ToastType } from './toast' +export { + settingsStore, + theme, + accentColor, + font, + resolvedTheme, + settingsLoading, + keyNotationFormat, + language, + dateFormat, + exportFormat, + autoAnalyzeOnImport, + autoSyncOnConnect, + autoSyncOnChange, + continuousPlayback, + autoFetchMetadata, + transferTagsOnImport, + removeReleaseAfterImport, + ignoredDeviceIds, + lastBackupAt, + backupFrequency, + lastBackupType, + hasCompletedOnboarding, + hasCompletedWizard, + audioDevice, + audioDevices, +} from './settings' +export type { SettingsStoreHooks } from './settings' +export { + discoveryStore, + sortedReleases, + displayedReleases, + releaseCount, + isDiscoveryLoading, + refreshingReleaseIds, +} from './discovery' +export { expandedReleaseIds } from './expandedReleases' +export { discoveryPlaylistStore, discoveryPlaylistReleases } from './discoveryPlaylist' diff --git a/src/lib/stores/player.ts b/shared/stores/player.ts similarity index 97% rename from src/lib/stores/player.ts rename to shared/stores/player.ts index d56c7672..5c5f76ec 100644 --- a/src/lib/stores/player.ts +++ b/shared/stores/player.ts @@ -1,11 +1,10 @@ import { writable, derived, get } from 'svelte/store' -import type { Track, PlaybackState, PreviewInfo, DiscoveryRelease } from '$lib/types' -import * as playerApi from '$lib/api/player' -import * as discoveryApi from '$lib/api/discovery' -import * as previewPlayer from '$lib/services/previewPlayer' -import { missingTracksStore } from './missingTracks' +import type { Track, PlaybackState, PreviewInfo, DiscoveryRelease } from '../types' +import * as playerApi from '../api/player' +import * as discoveryApi from '../api/discovery' +import * as previewPlayer from '../services/previewPlayer' import { toastStore } from './toast' -import { translate } from '$lib/i18n' +import { translate } from '../i18n' import { getStoredNumber, setStoredNumber, @@ -13,7 +12,7 @@ import { setStoredString, getStoredBoolean, setStoredBoolean, -} from '$lib/utils/storage' +} from '../utils/storage' // ============================================================================= // State @@ -67,9 +66,14 @@ const initialState: PlayerState = { // Store // ============================================================================= +export interface PlayerStoreHooks { + onTrackMissing?: (trackId: string) => void +} + function createPlayerStore() { const { subscribe, set, update } = writable(initialState) + let hooks: PlayerStoreHooks = {} let positionInterval: ReturnType | null = null let onTrackEndCallback: (() => void) | null = null let previewRetryAttempted = false @@ -265,6 +269,13 @@ function createPlayerStore() { return { subscribe, + /** + * Register hooks for desktop-only store interactions. + */ + registerHooks(h: PlayerStoreHooks) { + hooks = h + }, + /** * Play a library track. If preview is active, stop it first. */ @@ -304,7 +315,7 @@ function createPlayerStore() { } catch (error) { const errorMsg = error instanceof Error ? error.message : 'Failed to play track' if (errorMsg.toLowerCase().includes('file not found') || errorMsg.toLowerCase().includes('filenotfound')) { - missingTracksStore.markMissing(track.id) + hooks.onTrackMissing?.(track.id) } update((s) => ({ ...s, error: errorMsg })) } @@ -471,7 +482,7 @@ function createPlayerStore() { } catch (error) { const errorMsg = error instanceof Error ? error.message : 'Failed to play track' if (errorMsg.toLowerCase().includes('file not found') || errorMsg.toLowerCase().includes('filenotfound')) { - missingTracksStore.markMissing(state.currentTrack.id) + hooks.onTrackMissing?.(state.currentTrack.id) } update((s) => ({ ...s, error: errorMsg })) } diff --git a/src/lib/stores/playlists.ts b/shared/stores/playlists.ts similarity index 96% rename from src/lib/stores/playlists.ts rename to shared/stores/playlists.ts index e15823d7..2433fe0c 100644 --- a/src/lib/stores/playlists.ts +++ b/shared/stores/playlists.ts @@ -8,10 +8,9 @@ import type { BreadcrumbItem, MoveConflictResolution, MovePlaylistResult, -} from '$lib/types' -import * as playlistsApi from '$lib/api/playlists' +} from '../types' +import * as playlistsApi from '../api/playlists' import { toastStore } from './toast' -import { syncStore } from './sync' // ============================================================================= // State @@ -33,12 +32,25 @@ const initialState: PlaylistsState = { // Store // ============================================================================= +export interface PlaylistsStoreHooks { + onPlaylistChanged?: (playlistIds: string[]) => void +} + function createPlaylistsStore() { const { subscribe, set, update } = writable(initialState) + let hooks: PlaylistsStoreHooks = {} + return { subscribe, + /** + * Register hooks for desktop-only store interactions. + */ + registerHooks(h: PlaylistsStoreHooks) { + hooks = h + }, + /** * Load all playlists from both contexts */ @@ -117,8 +129,7 @@ function createPlaylistsStore() { playlists: state.playlists.map((p) => (p.id === id ? updated : p)), })) - // Notify sync store about playlist changes (for auto-sync) - syncStore.notifyPlaylistChanges([id]) + hooks.onPlaylistChanged?.([id]) return updated } catch (error) { @@ -233,8 +244,7 @@ function createPlaylistsStore() { playlists: state.playlists.map((p) => (p.id === playlistId ? updatedPlaylist : p)), })) - // Notify sync store about playlist changes (for auto-sync) - syncStore.notifyPlaylistChanges([playlistId]) + hooks.onPlaylistChanged?.([playlistId]) } catch (error) { update((state) => ({ ...state, @@ -255,8 +265,7 @@ function createPlaylistsStore() { playlists: state.playlists.map((p) => (p.id === playlistId ? updatedPlaylist : p)), })) - // Notify sync store about playlist changes (for auto-sync) - syncStore.notifyPlaylistChanges([playlistId]) + hooks.onPlaylistChanged?.([playlistId]) } catch (error) { update((state) => ({ ...state, @@ -272,8 +281,7 @@ function createPlaylistsStore() { try { await playlistsApi.reorderPlaylist(playlistId, trackIds) - // Notify sync store about playlist changes (for auto-sync) - syncStore.notifyPlaylistChanges([playlistId]) + hooks.onPlaylistChanged?.([playlistId]) } catch (error) { update((state) => ({ ...state, diff --git a/src/lib/stores/settings.ts b/shared/stores/settings.ts similarity index 94% rename from src/lib/stores/settings.ts rename to shared/stores/settings.ts index 1ca316b0..16fe1a1c 100644 --- a/src/lib/stores/settings.ts +++ b/shared/stores/settings.ts @@ -10,11 +10,9 @@ import type { DateFormat, ExportFormat, BackupFrequency, -} from '$lib/types' -import * as settingsApi from '$lib/api/settings' -import { rebuildMenu, type MenuTranslations } from '$lib/api/app' -import { setLanguage as setI18nLanguage, translate } from '$lib/i18n' -import { appStore } from './app' +} from '../types' +import * as settingsApi from '../api/settings' +import { setLanguage as setI18nLanguage, translate } from '../i18n' // ============================================================================= // State @@ -89,8 +87,14 @@ function getSystemTheme(): 'light' | 'dark' { // Store // ============================================================================= +export interface SettingsStoreHooks { + getAppName?: () => string + onLanguageChanged?: () => Promise +} + function createSettingsStore() { const { subscribe, set, update } = writable(initialState) + let hooks: SettingsStoreHooks = {} let systemThemeMediaQuery: MediaQueryList | null = null let mediaQueryHandler: ((e: MediaQueryListEvent) => void) | null = null @@ -154,23 +158,9 @@ function createSettingsStore() { systemThemeMediaQuery.addEventListener('change', mediaQueryHandler) } - function getAppName(): string { - const appState = get(appStore) - const environment = appState.info?.environment ?? 'development' - if (environment === 'production') { - return 'Crate' - } - if (environment === 'development') { - return 'Crate Dev' - } - // Other environments (alpha, beta, staging, etc.) use capitalized name - const suffix = environment.charAt(0).toUpperCase() + environment.slice(1) - return `Crate ${suffix}` - } - - function getMenuTranslations(): MenuTranslations { + function getMenuTranslations() { const t = get(translate) - const appName = getAppName() + const appName = hooks.getAppName?.() ?? 'Crate' return { // Menu titles file: t('menu.file'), @@ -235,17 +225,21 @@ function createSettingsStore() { } } - async function updateMenuTranslations() { - try { - await rebuildMenu(getMenuTranslations()) - } catch (error) { - console.error('Failed to rebuild menu:', error) - } - } - return { subscribe, + /** + * Register hooks for desktop-only store interactions. + */ + registerHooks(h: SettingsStoreHooks) { + hooks = h + }, + + /** + * Get translated menu labels for rebuilding the native menu. + */ + getMenuTranslations, + /** * Load settings from backend */ @@ -293,7 +287,7 @@ function createSettingsStore() { // Update i18n language and menu await setI18nLanguage(settings.language) await tick() - await updateMenuTranslations() + await hooks.onLanguageChanged?.() } catch (error) { update((s) => ({ ...s, @@ -384,7 +378,7 @@ function createSettingsStore() { update((s) => ({ ...s, language })) await setI18nLanguage(language) await tick() - await updateMenuTranslations() + await hooks.onLanguageChanged?.() persistToLocalStorage(state.theme, state.accentColor, language) try { diff --git a/src/lib/stores/tags.ts b/shared/stores/tags.ts similarity index 99% rename from src/lib/stores/tags.ts rename to shared/stores/tags.ts index 11c723a5..ee6b722f 100644 --- a/src/lib/stores/tags.ts +++ b/shared/stores/tags.ts @@ -1,6 +1,6 @@ import { writable, derived } from 'svelte/store' -import type { TagCategory, Tag, TagSelectionState, Track } from '$lib/types' -import * as tagsApi from '$lib/api/tags' +import type { TagCategory, Tag, TagSelectionState, Track } from '../types' +import * as tagsApi from '../api/tags' import { toastStore } from './toast' // ============================================================================= diff --git a/src/lib/stores/toast.ts b/shared/stores/toast.ts similarity index 98% rename from src/lib/stores/toast.ts rename to shared/stores/toast.ts index 1fee89a9..afe9757b 100644 --- a/src/lib/stores/toast.ts +++ b/shared/stores/toast.ts @@ -1,5 +1,5 @@ import { writable, derived } from 'svelte/store' -import * as diagnosticsApi from '$lib/api/diagnostics' +import * as diagnosticsApi from '../api/diagnostics' // ============================================================================= // Types diff --git a/src/lib/stores/ui.ts b/shared/stores/ui.ts similarity index 99% rename from src/lib/stores/ui.ts rename to shared/stores/ui.ts index 4301a992..f6fcd701 100644 --- a/src/lib/stores/ui.ts +++ b/shared/stores/ui.ts @@ -1,5 +1,5 @@ import { writable, derived } from 'svelte/store' -import type { ActiveView, SidebarView, TagFilterMode } from '$lib/types' +import type { ActiveView, SidebarView, TagFilterMode } from '../types' import { getStoredBoolean, getStoredNumber, @@ -7,7 +7,7 @@ import { setStoredBoolean, setStoredNumber, setStoredString, -} from '$lib/utils/storage' +} from '../utils/storage' // ============================================================================= // State diff --git a/src/lib/types/index.ts b/shared/types/index.ts similarity index 100% rename from src/lib/types/index.ts rename to shared/types/index.ts diff --git a/src/lib/utils/artwork.ts b/shared/utils/artwork.ts similarity index 79% rename from src/lib/utils/artwork.ts rename to shared/utils/artwork.ts index 8acbd7d7..8c3879b4 100644 --- a/src/lib/utils/artwork.ts +++ b/shared/utils/artwork.ts @@ -1,18 +1,15 @@ import { convertFileSrc } from '@tauri-apps/api/core' -import { get } from 'svelte/store' -import { appDataDir } from '$lib/stores/app' /** * Converts an artwork relative path to a displayable URL using Tauri's asset protocol. * Returns undefined if no artwork path or app data dir is available. * * @param artworkPath - Relative path like "artwork/{track_id}.webp" + * @param dataDir - Absolute path to the app data directory * @returns Asset URL for use in img src, or undefined */ -export function getArtworkUrl(artworkPath: string | null | undefined): string | undefined { +export function getArtworkUrl(artworkPath: string | null | undefined, dataDir: string | null): string | undefined { if (!artworkPath) return undefined - - const dataDir = get(appDataDir) if (!dataDir) return undefined const fullPath = `${dataDir}/${artworkPath}` diff --git a/src/lib/utils/bulkEdit.ts b/shared/utils/bulkEdit.ts similarity index 98% rename from src/lib/utils/bulkEdit.ts rename to shared/utils/bulkEdit.ts index b8868d0d..1b7d2217 100644 --- a/src/lib/utils/bulkEdit.ts +++ b/shared/utils/bulkEdit.ts @@ -1,4 +1,4 @@ -import type { ArtworkSource, BulkEditValue, BulkTrackInfo, Track } from '$lib/types' +import type { ArtworkSource, BulkEditValue, BulkTrackInfo, Track } from '../types' /** * Placeholder text for mixed values in bulk edit mode diff --git a/src/lib/utils/dom.ts b/shared/utils/dom.ts similarity index 94% rename from src/lib/utils/dom.ts rename to shared/utils/dom.ts index e0511e26..c25ead6b 100644 --- a/src/lib/utils/dom.ts +++ b/shared/utils/dom.ts @@ -1,4 +1,4 @@ -import { setDialogConflictingItemsEnabled } from '$lib/api/app' +import { setDialogConflictingItemsEnabled } from '../api/app' /** * Check if the currently focused element is an input or textarea. diff --git a/src/lib/utils/drag.ts b/shared/utils/drag.ts similarity index 100% rename from src/lib/utils/drag.ts rename to shared/utils/drag.ts diff --git a/src/lib/utils/format.ts b/shared/utils/format.ts similarity index 100% rename from src/lib/utils/format.ts rename to shared/utils/format.ts diff --git a/src/lib/utils/index.ts b/shared/utils/index.ts similarity index 100% rename from src/lib/utils/index.ts rename to shared/utils/index.ts diff --git a/src/lib/utils/playlist.ts b/shared/utils/playlist.ts similarity index 95% rename from src/lib/utils/playlist.ts rename to shared/utils/playlist.ts index 0a0cdd59..d33587f4 100644 --- a/src/lib/utils/playlist.ts +++ b/shared/utils/playlist.ts @@ -1,4 +1,4 @@ -import type { Playlist } from '$lib/types' +import type { Playlist } from '../types' /** * Find a playlist by its ID. diff --git a/src/lib/utils/position.ts b/shared/utils/position.ts similarity index 100% rename from src/lib/utils/position.ts rename to shared/utils/position.ts diff --git a/src/lib/utils/selection.ts b/shared/utils/selection.ts similarity index 100% rename from src/lib/utils/selection.ts rename to shared/utils/selection.ts diff --git a/src/lib/utils/smartRules.ts b/shared/utils/smartRules.ts similarity index 99% rename from src/lib/utils/smartRules.ts rename to shared/utils/smartRules.ts index 25939686..503bfa22 100644 --- a/src/lib/utils/smartRules.ts +++ b/shared/utils/smartRules.ts @@ -7,7 +7,7 @@ import type { EnumOperator, TagOperator, TagCategory, -} from '$lib/types' +} from '../types' // ============================================================================= // Field Definitions diff --git a/src/lib/utils/sorting.ts b/shared/utils/sorting.ts similarity index 96% rename from src/lib/utils/sorting.ts rename to shared/utils/sorting.ts index 8ae08218..40430d92 100644 --- a/src/lib/utils/sorting.ts +++ b/shared/utils/sorting.ts @@ -1,5 +1,5 @@ -import type { Track, SortConfig, TrackSortField, SortDirection, TrackColor } from '$lib/types' -import { COLOR_SORT_ORDER } from '$lib/types' +import type { Track, SortConfig, TrackSortField, SortDirection, TrackColor } from '../types' +import { COLOR_SORT_ORDER } from '../types' /** * Sort tracks by the given configuration diff --git a/src/lib/utils/storage.ts b/shared/utils/storage.ts similarity index 100% rename from src/lib/utils/storage.ts rename to shared/utils/storage.ts diff --git a/src/lib/utils/tagComputation.ts b/shared/utils/tagComputation.ts similarity index 98% rename from src/lib/utils/tagComputation.ts rename to shared/utils/tagComputation.ts index fd454168..1fe2d540 100644 --- a/src/lib/utils/tagComputation.ts +++ b/shared/utils/tagComputation.ts @@ -1,4 +1,4 @@ -import type { TagCategory, TagSelectionState, DiscoveryRelease } from '$lib/types' +import type { TagCategory, TagSelectionState, DiscoveryRelease } from '../types' import { SvelteMap } from 'svelte/reactivity' export function computeDiscoveryTagStates( diff --git a/src/lib/utils/transitions.ts b/shared/utils/transitions.ts similarity index 100% rename from src/lib/utils/transitions.ts rename to shared/utils/transitions.ts diff --git a/src/lib/utils/virtualizer.svelte.ts b/shared/utils/virtualizer.svelte.ts similarity index 99% rename from src/lib/utils/virtualizer.svelte.ts rename to shared/utils/virtualizer.svelte.ts index 3653f6ff..707c51c6 100644 --- a/src/lib/utils/virtualizer.svelte.ts +++ b/shared/utils/virtualizer.svelte.ts @@ -85,7 +85,6 @@ export function createVirtualList(options: VirtualListOptions) { // re-trigger the $effect.pre → syncState() → infinite loop. // Writes still fire notifications, so {#each} templates update. untrack(() => { - // @ts-expect-error we know totalSize = instance.getTotalSize() // Check if we can update in-place (same keys in same order). diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 7f229a39..9b9e0e7c 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -7,7 +7,7 @@ "beforeDevCommand": "yarn dev:vite", "devUrl": "http://localhost:1420", "beforeBuildCommand": "yarn build:vite", - "frontendDist": "../build" + "frontendDist": "../apps/desktop/build" }, "app": { "windows": [