Skip to content

Commit

Permalink
Separated out project list to other component.
Browse files Browse the repository at this point in the history
Opened project is saved using session storage.
Added a message for when no project could be loaded when going into /editor route.
Fixed library not showing images correctly and a type error.
Moved creating and opening projects to project store.
Fixed projects not being able to load when a media item associated with it is unavailable.
Added more functionality to library items.
  • Loading branch information
Joery-M committed Apr 16, 2024
1 parent 6e5fb4e commit 856e1e8
Show file tree
Hide file tree
Showing 10 changed files with 382 additions and 210 deletions.
69 changes: 33 additions & 36 deletions packages/safelight/src/components/Editor/Library/Library.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
scroll-height="400px"
class="flex h-full flex-col"
data-key="id"
@dblclick="fileDialog.open()"
>
<template #header>
<Toolbar class="border-none p-0">
Expand Down Expand Up @@ -38,66 +37,56 @@
/>
</InputGroup>
</template>
<template #end>
<Button title="Load file" rounded @click="fileDialog.open()">
<template #icon>
<PhUpload />
</template>
</Button>
</template>
</Toolbar>
</template>
<template #list="{ items }: { items: UnwrapRef<Media>[] }">
<template #list="{ items }: { items: Media[] }">
<div
class="grid-nogutter grid"
class="grid-nogutter grid h-full select-none"
role="grid"
style="grid-template-columns: repeat(auto-fill, minmax(150px, 1fr))"
style="
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
grid-template-rows: min-content;
"
@dblclick.self="fileDialogOpenDblClick"
>
<div
v-for="item in items"
:key="item.id"
role="gridcell"
class="border-round m-1 flex min-h-32 flex-col rounded-md border-solid border-white/10"
class="border-round m-1 flex min-h-32 select-text flex-col rounded-md border-solid border-white/10"
style="border-width: 1px"
:aria-label="item.name"
:aria-label="item.name.value"
>
<div
class="bg-checkerboard flex aspect-video w-full items-center justify-center"
>
<img
v-if="item.previewImage"
class="max-h-full max-w-full rounded-t-md"
:aria-label="'Preview image for ' + item.name"
:src="item.previewImage"
/>
<Skeleton
v-else
class="max-h-full max-w-full rounded-none rounded-t-md"
height="100%"
width="100%"
/>
</div>
<p
v-tooltip.bottom="{ value: item.name.value, showDelay: 1000 }"
class="m-0 mt-1 max-w-full overflow-x-hidden overflow-ellipsis text-base"
>
{{ item.name.value }}
</p>
<p v-if="item.duration > 0">
{{ item.duration }}
</p>
<LibraryItem :item="item" />
</div>
</div>
</template>
<template #empty>
<div class="grid h-full place-items-center" @dblclick="fileDialog.open()">
<label class="select-none opacity-60">No media imported</label>
<div
class="grid h-full select-none place-items-center opacity-60"
@dblclick="fileDialogOpenDblClick"
>
<label v-if="media.length == 0"> No media imported </label>
<label v-else>No media found</label>
</div>
</template>
</DataView>
</template>

<script setup lang="ts">
import { PhMagnifyingGlass, PhSortDescending } from '@phosphor-icons/vue';
import { PhMagnifyingGlass, PhSortDescending, PhUpload } from '@phosphor-icons/vue';
import Media from '@safelight/shared/Media/Media';
import fuzzysearch from 'fuzzysearch';
import MimeMatcher from 'mime-matcher';
import InputGroup from 'primevue/inputgroup';
import InputGroupAddon from 'primevue/inputgroupaddon';
import type { UnwrapRef } from 'vue';
useDropZone(document.body, {
onDrop(files) {
Expand Down Expand Up @@ -164,6 +153,8 @@ function sortAndFilter() {
return item1.duration.value - item2.duration.value;
case 'File type':
return collator.compare(ext1, ext2);
case 'Media type':
return collator.compare(item1.type.toString(), item1.type.toString());
default:
return collator.compare(item1.name.value, item2.name.value);
}
Expand All @@ -172,7 +163,13 @@ function sortAndFilter() {
sortedAndFiltered.value = filtered;
}
type sortOptions = 'Name' | 'Duration' | 'File type';
function fileDialogOpenDblClick(event: MouseEvent) {
event.preventDefault();
document.getSelection()?.removeAllRanges();
fileDialog.open();
}
type sortOptions = 'Name' | 'Duration' | 'File type' | 'Media type';
</script>

<style lang="scss" scoped>
Expand Down
113 changes: 113 additions & 0 deletions packages/safelight/src/components/Editor/Library/LibraryItem.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
<template>
<div class="bg-checkerboard flex aspect-video w-full items-center justify-center">
<img
v-if="$props.item.previewImage.value"
class="max-h-full max-w-full rounded-t-md"
:aria-label="'Preview image for ' + $props.item.name.value"
:src="$props.item.previewImage.value"
/>
<Skeleton
v-else
class="max-h-full max-w-full rounded-none rounded-t-md"
height="100%"
width="100%"
/>
</div>
<div class="flex items-center gap-1 px-1">
<p
v-tooltip.bottom="{ value: $props.item.name.value, showDelay: 500 }"
class="flex-1 overflow-x-hidden overflow-ellipsis whitespace-nowrap text-base"
>
{{ $props.item.name.value }}
</p>
<Button
title="Options"
text
rounded
severity="secondary"
aria-haspopup="true"
aria-controls="library_item_menu"
@click="overlay?.show"
>
<template #icon>
<PhDotsThreeVertical size="20" />
</template>
</Button>
</div>
<OverlayPanel id="library_item_menu" ref="overlay">
<Toolbar>
<template #center>
<Button
v-tooltip.bottom="{ value: 'Delete', showDelay: 500 }"
severity="contrast"
text
:disabled="hasItemInTimeline"
@click="alertt('yea no')"
>
<template #icon>
<PhTrash />
</template>
</Button>
</template>
</Toolbar>
<Menu :model="menuItems" />
</OverlayPanel>
</template>
<script setup lang="ts">
import { PhTrash, type PhDotsThreeVertical } from '@phosphor-icons/vue';
import type Media from '@safelight/shared/Media/Media';
import type Menu from 'primevue/menu';
import type { MenuItem } from 'primevue/menuitem';
import type OverlayPanel from 'primevue/overlaypanel';
const props = defineProps<{
item: Media;
}>();
const project = useProject();
const menuItems = ref<MenuItem[]>([
{
label: 'Temp'
}
]);
// My god
// TODO: Not this
const hasItemInTimeline = computed(() => {
console.log('A');
return project.project
? project.project.timelines.some(
(t) =>
t.isSimpleTimeline() &&
t.items.some(
(i) =>
i.isBaseTimelineItem() &&
i.isVideo() &&
i.media.value?.id == props.item.id
)
)
: false;
});
const alertt = (text: string) => window.alert(text);
const overlay = ref<OverlayPanel>();
</script>

<style lang="scss">
#library_item_menu .p-overlaypanel-content {
padding: 0 !important;
> .p-menu {
border: none;
}
> .p-toolbar {
@apply border-surface-100/10 rounded-b-none p-1;
border-top-width: 0;
border-left-width: 0;
border-right-width: 0;
}
}
</style>
74 changes: 74 additions & 0 deletions packages/safelight/src/components/Menu/ProjectList/ProjectList.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<template>
<DataTable :value="projects" :loading>
<template #header>
<div class="align-items-center justify-content-between flex flex-wrap gap-2">
<h2 class="m-0 flex-1">Projects</h2>
<Button rounded title="Refresh list" @click="loadList()">
<template #icon>
<PhArrowsClockwise size="18" />
</template>
</Button>
<SplitButton
label="New project"
rounded
:model="projectTypes"
@click="project.new.newSimpleProject()"
/>
</div>
</template>
<Column field="name" header="Project" />
<Column field="type" header="Type" />
<Column header="Modified">
<template #body="slotProps">
{{ formatDateTime((slotProps.data as StoredProject).updated) }}
</template>
</Column>
<Column>
<template #body="slotProps">
<Button @click="project.openProject(slotProps.data)">Open</Button>
</template>
</Column>
</DataTable>
</template>

<script setup lang="ts">
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
},
{ label: 'Test', command() {} }
] as const;
const projects = ref<StoredProject[]>([]);
const loading = ref(true);
onMounted(() => {
loadList();
});
function loadList() {
loading.value = true;
Storage.getProjects()
.then((p) => {
projects.value = p;
})
.catch((err) => {
console.error(err);
})
.finally(() => {
loading.value = false;
});
}
function formatDateTime(dt: string) {
const date = DateTime.fromISO(dt).toLocal();
return date.toLocaleString({ dateStyle: 'long', timeStyle: 'short' });
}
</script>
6 changes: 2 additions & 4 deletions packages/safelight/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@ import { createRouter, createWebHistory } from 'vue-router/auto';
import App from './App.vue';

import PrimeVue, { type PrimeVueConfiguration } from 'primevue/config';
import ConfirmationService from 'primevue/confirmationservice';
import 'primevue/resources/primevue.min.css';
import 'primevue/resources/themes/aura-dark-amber/theme.css';
import Tooltip from 'primevue/tooltip';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
// import SafelightTheme from '@/@core/Safelight';

import './style.scss';

Expand All @@ -24,10 +22,10 @@ export const pinia = createPinia();
app.use(pinia);
app.use(router);
app.use(PrimeVue, {
// pt: SafelightTheme,
inputStyle: 'outlined',
ripple: false
} as PrimeVueConfiguration);
app.use(ConfirmationService);

// Directives
app.directive('tooltip', Tooltip);
Expand Down
Loading

0 comments on commit 856e1e8

Please sign in to comment.