diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 3afc69ef..fa9e40a7 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -4,6 +4,8 @@ "esbenp.prettier-vscode", "bradlc.vscode-tailwindcss", "vivaxy.vscode-conventional-commits", - "vue.volar" + "vue.volar", + "github.vscode-pull-request-github", + "github.vscode-github-actions" ] } diff --git a/packages/safelight/src/components/Editor/Library/Library.vue b/packages/safelight/src/components/Editor/Library/Library.vue index 20baf034..1d4390d3 100644 --- a/packages/safelight/src/components/Editor/Library/Library.vue +++ b/packages/safelight/src/components/Editor/Library/Library.vue @@ -5,13 +5,24 @@ scroll-height="400px" class="flex h-full flex-col" data-key="id" + :pt="{ + header: { + class: 'p-1' + }, + content: { + style: 'flex: 1;' + }, + emptyMessage: { + style: 'height: 100%;' + } + }" > @@ -81,7 +94,6 @@ - - diff --git a/packages/safelight/src/components/Editor/Library/LibraryItem.vue b/packages/safelight/src/components/Editor/Library/LibraryItem.vue index da38049f..26767d8e 100644 --- a/packages/safelight/src/components/Editor/Library/LibraryItem.vue +++ b/packages/safelight/src/components/Editor/Library/LibraryItem.vue @@ -1,8 +1,10 @@ - - + + - + diff --git a/packages/safelight/src/components/InplaceRename.vue b/packages/safelight/src/components/InplaceRename.vue index 5becf148..da8edb4b 100644 --- a/packages/safelight/src/components/InplaceRename.vue +++ b/packages/safelight/src/components/InplaceRename.vue @@ -1,6 +1,6 @@ @@ -29,7 +29,7 @@ @@ -41,12 +41,10 @@ import { Storage, type StoredProject } from '@safelight/shared/base/Storage'; import { DateTime } from 'luxon'; import type { MenuItem } from 'primevue/menuitem'; -const project = useProject(); - const projectTypes: MenuItem[] = [ { label: 'Simple', - command: project.new.newSimpleProject + command: () => CurrentProject.newSimpleProject() }, { label: 'Test', command() {} } ] as const; @@ -81,7 +79,7 @@ function formatDateTime(dt: string) { } async function setProjectName(newName: string, project: StoredProject) { - const storage = await getStorageControllerForProject(project); + const storage = await CurrentProject.getStorageControllerForProject(project); await storage?.UpdateStoredProject({ id: project.id, name: newName }); loadList(); } diff --git a/packages/safelight/src/main.ts b/packages/safelight/src/main.ts index 26e7748f..551cb9d7 100644 --- a/packages/safelight/src/main.ts +++ b/packages/safelight/src/main.ts @@ -28,6 +28,9 @@ app.use(PrimeVue, { } as PrimeVueConfiguration); app.use(ConfirmationService); +// Phosphor icons +app.provide('size', 18); + // Directives app.directive('tooltip', Tooltip); app.directive('focustrap', FocusTrap); diff --git a/packages/safelight/src/stores/currentProject.ts b/packages/safelight/src/stores/currentProject.ts new file mode 100644 index 00000000..0858246e --- /dev/null +++ b/packages/safelight/src/stores/currentProject.ts @@ -0,0 +1,138 @@ +/* eslint-disable no-dupe-class-members */ +import { router } from '@/main'; +import type BaseProject from '@safelight/shared/base/Project'; +import type { ProjectType } from '@safelight/shared/base/Project'; +import BaseStorageController, { Storage, type StoredProject } from '@safelight/shared/base/Storage'; +import MediaManager from '@safelight/shared/Storage/MediaManager'; +import { DateTime } from 'luxon'; + +export class CurrentProject { + // see #14 for why + public static project = shallowRef(); + public static isLoaded = ref(false); + + public static async openProject( + selectedProject: StoredProject | SessionProject, + goToEditor = true + ) { + this.isLoaded.value = false; + const storageType = await this.getStorageControllerForProject(selectedProject.type); + if (!storageType) { + throw new Error('Could not find storage controller for project type'); + } + + Storage.setStorage(storageType); + + const project = await Storage.getStorage().LoadProject(selectedProject.id); + + if (project) { + this.setProject(project); + this.setSessionProject(selectedProject); + if (goToEditor) await this.toEditor(); + this.isLoaded.value = true; + } else { + console.error('Could not load project'); + } + } + + public static async toEditor() { + await router.push('/editor'); + } + + public static async newSimpleProject(goToEditor = true) { + const IndexedDbStorageController = ( + await import('@safelight/shared/Storage/IndexedDbStorage') + ).default; + Storage.setStorage(new IndexedDbStorageController()); + const SimpleProject = (await import('@safelight/shared/Project/SimpleProject')).default; + this.setProject(new SimpleProject()); + + if (goToEditor) await this.toEditor(); + } + + public static getStorageControllerForProject( + project: ProjectType + ): Promise; + public static getStorageControllerForProject( + project: StoredProject + ): Promise; + public static async getStorageControllerForProject(project: StoredProject | ProjectType) { + const type = typeof project === 'string' ? project : project.type; + if (type == 'Simple') { + return new (await import('@safelight/shared/Storage/IndexedDbStorage')).default(); + } else { + console.error('Project type not supported'); + } + } + + public static setProject(newProject: BaseProject) { + this.project.value = newProject; + this.isLoaded.value = true; + } + + public static setSessionProject(project: StoredProject | BaseProject | SessionProject) { + const sessionProject: SessionProject = { + id: project.id, + lastOpened: DateTime.now().toISO(), + type: project.type + }; + sessionStorage.setItem('project', JSON.stringify(sessionProject)); + } + public static getSessionProject() { + const item = window.sessionStorage.getItem('project'); + if (!item) return; + return JSON.parse(item) as SessionProject; + } + public static clearSessionProject() { + sessionStorage.removeItem('project'); + } + + // Might want to move this to BaseProject or SimpleProject + public static loadFile(file: File) { + return new Promise((resolve) => { + const storingProcessing = useObservable(MediaManager.StoreMedia(file)); + watch(storingProcessing, (s) => { + console.log(s?.type, s?.hashProgress); + }); + + watch(storingProcessing, async () => { + if (storingProcessing.value && storingProcessing.value.type == 'done') { + const existingMedia = this.project.value!.media.some( + (m) => m.id == storingProcessing.value!.id + ); + + if (!existingMedia) { + const media = await Storage.getStorage().LoadMedia( + storingProcessing.value.id! + ); + + if (media) { + this.project.value!.media.push(media); + this.save(); + } + } + + resolve(); + } + }); + }); + } + + public static async save() { + if (this.project.value) await Storage.getStorage().SaveProject(this.project.value); + } + + public static async beforeExit(clearSession = true) { + if (this.project.value) { + if (clearSession) this.clearSessionProject(); + await this.save(); + this.project.value = undefined; + } + } +} + +export interface SessionProject { + id: string; + type: ProjectType; + lastOpened: string; +} diff --git a/packages/safelight/src/stores/useProject.ts b/packages/safelight/src/stores/useProject.ts index 8f6fa84f..42068512 100644 --- a/packages/safelight/src/stores/useProject.ts +++ b/packages/safelight/src/stores/useProject.ts @@ -1,113 +1,7 @@ -import { router } from '@/main'; -import type BaseProject from '@safelight/shared/base/Project'; -import BaseStorageController, { Storage, type StoredProject } from '@safelight/shared/base/Storage'; -import MediaManager from '@safelight/shared/Storage/MediaManager'; - export const useProject = defineStore('Project', () => { const cursor = ref(0); - const timelineViewStart = ref(0); - const timelineViewEnd = ref(0); - - const project = shallowRef(); - const isLoaded = ref(false); - - function setProject(newProject: BaseProject) { - project.value = newProject; - isLoaded.value = true; - - useSessionStorage('project', '').value = newProject.id; - } - - function loadFile(file: File) { - return new Promise((resolve) => { - const storingProcessing = useObservable(MediaManager.StoreMedia(file)); - watch(storingProcessing, (s) => { - console.log(s?.type, s?.hashProgress); - }); - - watch(storingProcessing, async () => { - if (storingProcessing.value && storingProcessing.value.type == 'done') { - const existingMedia = project.value!.media.some( - (m) => m.id == storingProcessing.value!.id - ); - - if (!existingMedia) { - const media = await Storage.getStorage().LoadMedia( - storingProcessing.value.id! - ); - - if (media) { - project.value!.media.push(media); - save(); - } - } - - resolve(); - } - }); - }); - } - - function save() { - if (project.value) Storage.getStorage().SaveProject(project.value); - } return { - project, - setProject, - loadFile, - isLoaded, - cursor, - timelineViewStart, - timelineViewEnd, - save, - openProject, - new: { - newSimpleProject - } + cursor }; }); - -async function newSimpleProject() { - const IndexedDbStorageController = (await import('@safelight/shared/Storage/IndexedDbStorage')) - .default; - Storage.setStorage(new IndexedDbStorageController()); - const projectStore = useProject(); - const SimpleProject = (await import('@safelight/shared/Project/SimpleProject')).default; - projectStore.setProject(new SimpleProject()); - - await toEditor(); -} - -export async function getStorageControllerForProject( - project: StoredProject -): Promise { - if (project.type == 'Simple') { - return new (await import('@safelight/shared/Storage/IndexedDbStorage')).default(); - } else { - console.error('Project type not supported'); - } -} - -async function openProject(selectedProject: StoredProject) { - const storageType = await getStorageControllerForProject(selectedProject); - if (!storageType) { - throw new Error('Could not find storage controller for project type'); - } - - const projectStore = useProject(); - Storage.setStorage(storageType); - - const project = await Storage.getStorage().LoadProject(selectedProject.id); - - if (project) { - projectStore.setProject(project); - await toEditor(); - } else { - console.error('Could not load project'); - } -} - -async function toEditor() { - await router.push('/editor'); -} diff --git a/packages/safelight/src/views/Editor/Editor.vue b/packages/safelight/src/views/Editor/Editor.vue index 7a9e4c23..0a09ecdc 100644 --- a/packages/safelight/src/views/Editor/Editor.vue +++ b/packages/safelight/src/views/Editor/Editor.vue @@ -1,68 +1,115 @@