obsidian-visualiser/pages/explore/edit/index.vue

255 lines
8.3 KiB
Vue

<template>
<Head>
<Title>d[any] - Modification</Title>
</Head>
<div class="flex flex-1 flex-col xl:-mx-12 xl:-my-8 lg:-mx-8 lg:-my-6 -mx-6 -my-3 overflow-hidden">
<div class="z-50 flex w-full items-center justify-between border-b border-light-35 dark:border-dark-35 px-2">
<div class="flex items-center px-2 gap-4">
<!-- <CollapsibleTrigger asChild>
<Button icon class="!bg-transparent group md:hidden">
<Icon class="group-data-[state=open]:hidden" icon="radix-icons:hamburger-menu" />
<Icon class="group-data-[state=closed]:hidden" icon="radix-icons:cross-1" />
</Button>
</CollapsibleTrigger> -->
<NuxtLink class="text-light-100 dark:text-dark-100 hover:text-opacity-70 m-2 flex items-center gap-4" aria-label="Accueil" :to="{ path: '/', force: true }">
<Avatar src="/logo.dark.svg" class="dark:block hidden" />
<Avatar src="/logo.light.svg" class="block dark:hidden" />
<span class="text-xl max-md:hidden">d[any]</span>
</NuxtLink>
</div>
<div class="flex items-center px-2 gap-4">
<NuxtLink class="text-light-100 dark:text-dark-100 hover:text-light-70 dark:hover:text-dark-70" :to="{ name: 'user-login' }">{{ user!.username }}</NuxtLink>
</div>
</div>
<div class="flex flex-1 flex-row relative h-screen overflow-hidden">
<div class="bg-light-0 dark:bg-dark-0 z-40 w-screen md:w-[18rem] border-r border-light-30 dark:border-dark-30 flex flex-col justify-between my-2 max-md:data-[state=closed]:hidden">
<div class="flex-1 px-2 max-w-full max-h-full overflow-y-auto overflow-x-hidden" ref="tree"></div>
<div class="xl:px-12 px-6 pt-4 pb-2 text-center text-xs text-light-60 dark:text-dark-60">
<NuxtLink class="hover:underline italic" :to="{ name: 'roadmap' }">Roadmap</NuxtLink> - <NuxtLink class="hover:underline italic" :to="{ name: 'legal' }">Mentions légales</NuxtLink>
<p>Copyright Peaceultime - 2025</p>
</div>
</div>
<div class="flex flex-1 flex-row max-h-full overflow-hidden" ref="container"></div>
</div>
</div>
</template>
<script setup lang="ts">
import { Content, Editor } from '#shared/content.util';
import { loading } from '#shared/proses';
definePageMeta({
rights: ['admin', 'editor'],
layout: 'null',
});
const { user } = useUserSession();
const tree = useTemplateRef('tree'), container = useTemplateRef('container');
let editor: Editor;
onMounted(async () => {
if(tree.value && container.value && await Content.ready)
{
const load = loading('normal');
tree.value.appendChild(load);
editor = new Editor();
tree.value.replaceChild(editor.tree.container, load);
container.value.appendChild(editor.container);
}
});
onBeforeUnmount(() => {
editor?.unmount();
})
/* import { Icon } from '@iconify/vue/dist/iconify.js';
import type { Instruction } from '@atlaskit/pragmatic-drag-and-drop-hitbox/dist/types/tree-item';
import type { FileType, LocalContent, TreeItem } from '#shared/content.util';
import { DEFAULT_CONTENT, iconByType, Content, getPath } from '#shared/content.util';
import type { Preferences } from '~/types/general';
import { fakeA as proseA } from '#shared/proses';
import { parsePath } from '~/shared/general.util';
import type { CanvasContent } from '~/types/canvas';
export type TreeItemEditable = LocalContent &
{
parent?: string;
name?: string;
customPath?: boolean;
children?: TreeItemEditable[];
}
definePageMeta({
rights: ['admin', 'editor'],
layout: 'null',
});
const { user } = useUserSession();
const router = useRouter();
const open = ref(true), topOpen = ref(true);
const toaster = useToast();
const saveStatus = ref<'idle' | 'pending' | 'success' | 'error'>('idle');
let navigation = Content.tree as TreeItemEditable[];
const selected = ref<TreeItemEditable>();
const preferences = useCookie<Preferences>('preferences', { default: () => ({ markdown: { editing: 'split' }, canvas: { gridSnap: true, neighborSnap: true, spacing: 32 } }), watch: true, maxAge: 60*60*24*31 });
watch(selected, async (value, old) => {
if(selected.value)
{
if(!selected.value.content && selected.value.path)
{
selected.value = await Content.content(selected.value.path);
}
router.replace({ hash: '#' + encodeURIComponent(selected.value!.path || getPath(selected.value!)) });
}
else
{
router.replace({ hash: '' });
}
})
const debouncedSave = useDebounceFn(save, 60000, { maxWait: 180000 });
useShortcuts({
//meta_s: { usingInput: true, handler: () => save(), prevent: true },
meta_n: { usingInput: true, handler: () => add('markdown'), prevent: true },
meta_shift_n: { usingInput: true, handler: () => add('folder'), prevent: true },
meta_shift_z: { usingInput: true, handler: () => router.push({ name: 'explore-path', params: { path: 'index' } }), prevent: true }
})
function add(type: FileType): void
{
if(!navigation)
{
return;
}
const news = [...tree.search(navigation, 'title', 'Nouveau')].filter((e, i, a) => a.indexOf(e) === i);
const title = `Nouveau${news.length > 0 ? ' (' + news.length +')' : ''}`;
const item: TreeItemEditable = { navigable: true, private: false, parent: '', path: '', title: title, name: parsePath(title), type: type, order: 0, children: [], customPath: false, content: DEFAULT_CONTENT[type], owner: -1, timestamp: new Date(), visit: 0 };
if(!selected.value)
{
navigation = [...navigation, item];
}
else if(selected.value?.children)
{
item.parent = getPath(selected.value);
navigation = tree.insertChild(navigation, item.parent, item);
}
else
{
navigation = tree.insertAfter(navigation, getPath(selected.value), item);
}
}
function updateTree(instruction: Instruction, itemId: string, targetId: string) : TreeItemEditable[] | undefined {
if(!navigation)
return;
const item = tree.find(navigation, itemId);
const target = tree.find(navigation, targetId);
if(!item)
return;
if (instruction.type === 'reparent') {
const path = tree.getPathToItem({
current: navigation,
targetId: targetId,
});
if (!path) {
console.error(`missing ${path}`);
return;
}
const desiredId = path[instruction.desiredLevel];
let result = tree.remove(navigation, itemId);
result = tree.insertAfter(result, desiredId, item);
return result;
}
// the rest of the actions require you to drop on something else
if (itemId === targetId)
return navigation;
if (instruction.type === 'reorder-above') {
let result = tree.remove(navigation, itemId);
result = tree.insertBefore(result, targetId, item);
return result;
}
if (instruction.type === 'reorder-below') {
let result = tree.remove(navigation, itemId);
result = tree.insertAfter(result, targetId, item);
return result;
}
if (instruction.type === 'make-child') {
if(!target || target.type !== 'folder')
return;
let result = tree.remove(navigation, itemId);
result = tree.insertChild(result, targetId, item);
rebuildPath([item], targetId);
return result;
}
return navigation;
}
function transform(items: TreeItem[] | undefined): TreeItemEditable[] | undefined
{
return items?.map(e => ({
...e,
parent: e.path.substring(0, e.path.lastIndexOf('/')),
name: e.path.substring(e.path.lastIndexOf('/') + 1),
customPath: e.path.substring(e.path.lastIndexOf('/') + 1) !== parsePath(e.title),
children: transform(e.children)
})) as TreeItemEditable[] | undefined;
}
function flatten(items: TreeItemEditable[] | undefined): TreeItemEditable[]
{
return items?.flatMap(e => [e, ...flatten(e.children)]) ?? [];
}
function drop(instruction: Instruction, itemId: string, targetId: string)
{
navigation = updateTree(instruction, itemId, targetId) ?? navigation ?? [];
}
function rebuildPath(tree: TreeItemEditable[] | null | undefined, parentPath: string)
{
if(!tree)
return;
tree.forEach(e => {
e.parent = parentPath;
rebuildPath(e.children, getPath(e));
});
}
function save()
{
if(selected.value && selected.value.content)
{
selected.value.path = getPath(selected.value);
Content.save(selected.value);
}
}
const defaultExpanded = computed(() => {
if(router.currentRoute.value.hash)
{
const split = router.currentRoute.value.hash.substring(1).split('/');
split.forEach((e, i) => { if(i !== 0) split[i] = split[i - 1] + '/' + e });
return split;
}
});
watch(router.currentRoute, (value) => {
if(value && value.hash && navigation)
selected.value = tree.find(navigation, decodeURIComponent(value.hash.substring(1)));
else
selected.value = undefined;
}, { immediate: true }); */
</script>