basic job file function
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
import { Node, mergeAttributes } from '@tiptap/core';
|
||||
import { render } from 'solid-js/web';
|
||||
import { JobFileSelector } from '@/components/JobFileSelector';
|
||||
|
||||
export interface FileViewerOptions {
|
||||
HTMLAttributes: Record<string, any>;
|
||||
@@ -24,31 +26,16 @@ export const FileViewer = Node.create<FileViewerOptions>({
|
||||
addOptions() {
|
||||
return {
|
||||
HTMLAttributes: {
|
||||
class: 'file-viewer-node',
|
||||
class: 'file-viewer-node group relative',
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
addAttributes() {
|
||||
return {
|
||||
src: {
|
||||
default: null,
|
||||
parseHTML: element => {
|
||||
const iframe = element.querySelector('iframe');
|
||||
if (iframe) {
|
||||
return iframe.getAttribute('src');
|
||||
}
|
||||
return element.getAttribute('src');
|
||||
},
|
||||
renderHTML: attributes => {
|
||||
if (!attributes.src) {
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
src: attributes.src,
|
||||
};
|
||||
}
|
||||
},
|
||||
jobId: { default: null },
|
||||
collectionId: { default: 'Job_Info_Prod' },
|
||||
filename: { default: null },
|
||||
};
|
||||
},
|
||||
|
||||
@@ -61,8 +48,12 @@ export const FileViewer = Node.create<FileViewerOptions>({
|
||||
},
|
||||
|
||||
renderHTML({ HTMLAttributes }) {
|
||||
const { src, ...rest } = HTMLAttributes;
|
||||
return ['div', mergeAttributes(this.options.HTMLAttributes, rest, { 'data-type': 'file-viewer-wrapper', class: 'file-viewer-wrapper relative w-full my-4 rounded-xl overflow-hidden border border-border flex min-h-[400px] bg-muted/20' }),
|
||||
const { jobId, collectionId, filename, ...rest } = HTMLAttributes;
|
||||
let src = '';
|
||||
if (jobId && filename) {
|
||||
src = `https://pocketbase.ccllc.pro/api/files/${collectionId}/${jobId}/${filename}`;
|
||||
}
|
||||
return ['div', mergeAttributes(this.options.HTMLAttributes, rest, { 'data-type': 'file-viewer-wrapper', class: 'file-viewer-wrapper relative w-full my-4 rounded-xl overflow-hidden border border-border flex min-h-[500px] bg-muted/20' }),
|
||||
['iframe', { 'data-type': 'file-viewer', src: src, class: 'w-full h-full border-0 absolute inset-0' }]
|
||||
];
|
||||
},
|
||||
@@ -72,15 +63,17 @@ export const FileViewer = Node.create<FileViewerOptions>({
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.classList.add('file-viewer-wrapper', 'relative', 'w-full', 'my-4', 'rounded-xl', 'overflow-hidden', 'border', 'border-border', 'flex', 'bg-muted/10', 'group');
|
||||
|
||||
if (node.attrs.src) {
|
||||
// Typical file viewer mode
|
||||
wrapper.style.minHeight = '400px';
|
||||
const hasFile = node.attrs.jobId && node.attrs.filename;
|
||||
|
||||
if (hasFile) {
|
||||
// Viewer mode
|
||||
wrapper.style.minHeight = '500px';
|
||||
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.src = node.attrs.src;
|
||||
iframe.src = `https://pocketbase.ccllc.pro/api/files/${node.attrs.collectionId}/${node.attrs.jobId}/${node.attrs.filename}`;
|
||||
iframe.classList.add('w-full', 'h-full', 'border-0', 'absolute', 'inset-0');
|
||||
|
||||
// Add a small drag handle / delete button overlay that appears on hover
|
||||
// Delete button overlay
|
||||
const overlay = document.createElement('div');
|
||||
overlay.classList.add('absolute', 'top-2', 'right-2', 'hidden', 'group-hover:flex', 'bg-background/80', 'backdrop-blur-sm', 'p-1', 'rounded-lg', 'border', 'border-border', 'shadow-sm', 'z-10');
|
||||
|
||||
@@ -100,64 +93,34 @@ export const FileViewer = Node.create<FileViewerOptions>({
|
||||
overlay.appendChild(deleteBtn);
|
||||
wrapper.appendChild(iframe);
|
||||
wrapper.appendChild(overlay);
|
||||
} else {
|
||||
// Form mode
|
||||
wrapper.classList.add('items-center', 'justify-center', 'flex-col', 'p-8', 'gap-4');
|
||||
|
||||
const icon = document.createElement('div');
|
||||
// AppWindow Lucide Icon
|
||||
icon.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-muted-foreground/50"><rect x="2" y="4" width="20" height="16" rx="2"></rect><path d="M10 4v4"></path><path d="M2 8h20"></path><path d="M6 4v4"></path></svg>';
|
||||
|
||||
const title = document.createElement('div');
|
||||
title.textContent = 'Embed File or Website';
|
||||
title.classList.add('font-medium', 'text-sm', 'text-muted-foreground');
|
||||
|
||||
const form = document.createElement('form');
|
||||
form.classList.add('flex', 'w-full', 'max-w-md', 'gap-2', 'relative', 'z-10');
|
||||
|
||||
const input = document.createElement('input');
|
||||
input.type = 'url';
|
||||
input.placeholder = 'https://...';
|
||||
input.classList.add('flex-1', 'bg-background', 'border', 'border-border', 'rounded-lg', 'px-3', 'py-1.5', 'text-sm', 'outline-none', 'focus:ring-1', 'focus:ring-primary/50');
|
||||
|
||||
const button = document.createElement('button');
|
||||
button.type = 'submit';
|
||||
button.textContent = 'Embed';
|
||||
button.classList.add('bg-primary', 'text-primary-foreground', 'px-3', 'py-1.5', 'rounded-lg', 'text-sm', 'font-medium', 'hover:bg-primary/90', 'cursor-pointer');
|
||||
|
||||
form.onsubmit = (e) => {
|
||||
e.preventDefault();
|
||||
const url = input.value.trim();
|
||||
if (url && typeof getPos === 'function') {
|
||||
editor.commands.command(({ tr }) => {
|
||||
const pos = getPos();
|
||||
if (typeof pos === 'number') {
|
||||
tr.setNodeMarkup(pos, undefined, { src: url });
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
return {
|
||||
dom: wrapper,
|
||||
stopEvent: () => true,
|
||||
ignoreMutation: () => true,
|
||||
};
|
||||
} else {
|
||||
render(() => JobFileSelector({
|
||||
onSelectFile: (jobId: string, filename: string) => {
|
||||
if (typeof getPos === 'function') {
|
||||
editor.commands.command(({ tr }) => {
|
||||
const pos = getPos();
|
||||
if (typeof pos === 'number') {
|
||||
tr.setNodeMarkup(pos, undefined, { jobId, collectionId: 'Job_Info_Prod', filename });
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}), wrapper);
|
||||
|
||||
form.appendChild(input);
|
||||
form.appendChild(button);
|
||||
|
||||
wrapper.appendChild(icon);
|
||||
wrapper.appendChild(title);
|
||||
wrapper.appendChild(form);
|
||||
|
||||
// Clicking wrapper focuses input
|
||||
wrapper.onclick = () => {
|
||||
input.focus();
|
||||
return {
|
||||
dom: wrapper,
|
||||
stopEvent: () => true,
|
||||
ignoreMutation: () => true,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
dom: wrapper,
|
||||
stopEvent: () => true,
|
||||
ignoreMutation: () => true,
|
||||
};
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user