Update Version: 1.4.5
This commit is contained in:
@@ -96,7 +96,6 @@
|
||||
</script>
|
||||
|
||||
<div class="fixed right-0 top-0 bottom-0 w-80 bg-[var(--theme-bg)] backdrop-blur-xl border-l shadow-2xl flex flex-col z-[70] transform transition-transform duration-300 border-[var(--theme-border)]">
|
||||
<!-- Header -->
|
||||
<div class="flex items-center justify-between px-4 py-3 border-b bg-[var(--theme-bg)] text-[var(--theme-text)] border-[var(--theme-border)]">
|
||||
<div class="flex items-center gap-2">
|
||||
<Icon icon="mdi:comment-text-multiple-outline" class="text-lg" />
|
||||
@@ -108,7 +107,6 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Feed -->
|
||||
<div class="flex-1 overflow-y-auto p-4 space-y-4">
|
||||
{#if loading}
|
||||
<div class="flex justify-center items-center h-full">
|
||||
@@ -137,7 +135,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Actions -->
|
||||
<div class="flex opacity-0 group-hover:opacity-100 transition-opacity gap-1">
|
||||
{#if $userStore?.id === comment.user_id}
|
||||
<button onclick={() => deleteComment(comment.id)} class="p-1 hover:text-red-500 rounded hover:bg-red-50 dark:hover:bg-red-500/10 transition-colors" title="Delete">
|
||||
@@ -155,7 +152,6 @@
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Input Area -->
|
||||
<div class="p-4 border-t bg-[var(--theme-bg)] text-[var(--theme-text)] border-[var(--theme-border)]">
|
||||
<div class="relative">
|
||||
<textarea
|
||||
|
||||
@@ -248,9 +248,6 @@
|
||||
const msg = JSON.parse(data);
|
||||
if (msg.type === 'init') {
|
||||
lspInitialized = true;
|
||||
|
||||
// Recreate the client because the backend started a completely new LSP process
|
||||
// which requires a fresh 'initialize' handshake.
|
||||
client = new LSPClient({
|
||||
rootUri: msg.rootUri,
|
||||
timeout: 10000,
|
||||
@@ -262,9 +259,7 @@
|
||||
});
|
||||
return;
|
||||
}
|
||||
} catch (err) {
|
||||
// Fallthrough
|
||||
}
|
||||
} catch (err) {}
|
||||
}
|
||||
|
||||
let processedData = data;
|
||||
@@ -281,9 +276,7 @@
|
||||
for (let h of lsHandlers) h(processedData);
|
||||
};
|
||||
|
||||
lsSocket.onopen = () => {
|
||||
// Waiting for init message from server
|
||||
};
|
||||
lsSocket.onopen = () => {};
|
||||
}
|
||||
|
||||
connectLsp();
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
let isDrawing = false;
|
||||
let currentPath = $state<{x: number, y: number}[]>([]);
|
||||
|
||||
// New feature states
|
||||
let tool = $state<'pen' | 'highlighter' | 'eraser' | 'laser'>('laser');
|
||||
let selectedColor = $state('#ef4444');
|
||||
let showGrid = $state(false);
|
||||
@@ -23,7 +22,6 @@
|
||||
|
||||
const colors = ['#ef4444', '#f97316', '#eab308', '#22c55e', '#3b82f6', '#a855f7', '#ffffff', '#000000'];
|
||||
|
||||
// Map from slide index to image data url so we can persist drawings when switching slides
|
||||
let drawings = $state<Record<number, string>>({});
|
||||
let undoStack = $state<Record<number, string[]>>({});
|
||||
let redoStack = $state<Record<number, string[]>>({});
|
||||
@@ -41,7 +39,6 @@
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
// Find the preview svgs from the main DOM
|
||||
const previewContainers = document.querySelectorAll('.preview-container svg');
|
||||
const svgStrings: string[] = [];
|
||||
previewContainers.forEach(container => {
|
||||
@@ -49,7 +46,6 @@
|
||||
});
|
||||
svgs = svgStrings;
|
||||
|
||||
// Request fullscreen
|
||||
const el = document.getElementById('presentation-container');
|
||||
if (el && el.requestFullscreen) {
|
||||
el.requestFullscreen().catch(err => console.error(err));
|
||||
@@ -104,7 +100,6 @@
|
||||
|
||||
$effect(() => {
|
||||
if (canvas && currentSlide !== undefined && !showGrid) {
|
||||
// Resize canvas to match the svg
|
||||
const svgEl = document.getElementById('presentation-svg')?.querySelector('svg');
|
||||
if (svgEl) {
|
||||
const rect = svgEl.getBoundingClientRect();
|
||||
@@ -126,7 +121,6 @@
|
||||
ctx.lineCap = 'round';
|
||||
ctx.lineJoin = 'round';
|
||||
|
||||
// Load previous drawing if any
|
||||
if (drawings[currentSlide]) {
|
||||
const img = new Image();
|
||||
img.onload = () => {
|
||||
@@ -302,7 +296,6 @@
|
||||
|
||||
<div id="presentation-container" class="fixed inset-0 z-[100] flex flex-col items-center justify-center">
|
||||
|
||||
<!-- Laser Pointer Overlay -->
|
||||
{#if tool === 'laser' && laserPos.visible && !showGrid}
|
||||
<div
|
||||
class="pointer-events-none fixed z-[150] w-3 h-3 bg-red-500 rounded-full shadow-[0_0_15px_5px_rgba(239,68,68,0.8)] -translate-x-1/2 -translate-y-1/2"
|
||||
@@ -310,7 +303,6 @@
|
||||
></div>
|
||||
{/if}
|
||||
|
||||
<!-- Thumbnail Grid UI -->
|
||||
{#if showGrid}
|
||||
<div class="absolute inset-0 z-[50] p-8 overflow-y-auto">
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-6 max-w-7xl mx-auto pb-24">
|
||||
@@ -331,7 +323,6 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Top toolbar -->
|
||||
<div class="absolute top-0 inset-x-0 h-16 bg-gradient-to-b from-black/80 to-transparent flex items-center justify-between px-6 transition-opacity duration-300 z-[110] {uiVisible || showGrid ? 'opacity-100' : 'opacity-0'}">
|
||||
<div class="flex items-center gap-4 bg-zinc-900/80 backdrop-blur-md px-4 py-2 rounded-xl border shadow-2xl border-[var(--theme-border)]">
|
||||
<button class="p-2 rounded-lg transition-colors {tool === 'laser' ? 'bg-red-500/20 text-red-400' : 'text-gray-300 hover:bg-white/10'}" onclick={() => tool = 'laser'} title="Laser Pointer">
|
||||
@@ -383,19 +374,16 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Slide Area -->
|
||||
<div class="relative w-full h-full flex items-center justify-center p-8">
|
||||
{#if svgs.length > 0 && !showGrid}
|
||||
<div id="presentation-svg" class="relative max-h-full max-w-full shadow-2xl flex items-center justify-center bg-[var(--theme-bg)] text-[var(--theme-text)]">
|
||||
{@html svgs[currentSlide]}
|
||||
|
||||
<!-- Drawing Canvas Overlay -->
|
||||
<canvas
|
||||
bind:this={canvas}
|
||||
class="absolute inset-0 z-10 touch-none pointer-events-none"
|
||||
></canvas>
|
||||
|
||||
<!-- Active Stroke Canvas Overlay -->
|
||||
<canvas
|
||||
bind:this={activeCanvas}
|
||||
class="absolute inset-0 z-20 touch-none {tool === 'laser' ? 'cursor-none' : 'cursor-crosshair'}"
|
||||
@@ -413,7 +401,6 @@
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Bottom Navigation -->
|
||||
{#if svgs.length > 0}
|
||||
<div class="absolute bottom-6 flex items-center gap-4 bg-zinc-900/80 backdrop-blur-md px-6 py-3 rounded-full border shadow-2xl transition-opacity duration-300 z-[110] {uiVisible || showGrid ? 'opacity-100' : 'opacity-0'} border-[var(--theme-border)]">
|
||||
{#if svgs.length > 1}
|
||||
|
||||
@@ -414,7 +414,6 @@
|
||||
{title}
|
||||
</h1>
|
||||
|
||||
<!-- Sync status removed from here and moved to Footer -->
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@@ -55,7 +55,6 @@
|
||||
</script>
|
||||
|
||||
<div class="fixed right-0 top-0 bottom-0 w-80 bg-[var(--theme-bg)] backdrop-blur-xl border-l shadow-2xl flex flex-col z-[70] transform transition-transform duration-300 border-[var(--theme-border)]">
|
||||
<!-- Header -->
|
||||
<div class="flex items-center justify-between px-4 py-3 border-b bg-gray-50/50 bg-[var(--theme-bg)] text-[var(--theme-text)] border-[var(--theme-border)]">
|
||||
<div class="flex items-center gap-2">
|
||||
<Icon icon="mdi:history" class="text-lg" />
|
||||
@@ -67,7 +66,6 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Feed -->
|
||||
<div class="flex-1 overflow-y-auto p-4 space-y-4">
|
||||
{#if loading}
|
||||
<div class="flex justify-center items-center h-full">
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
} else {
|
||||
const button = e.currentTarget as HTMLElement;
|
||||
const rect = button.getBoundingClientRect();
|
||||
// If there's less than 200px below the button, open upwards
|
||||
if (window.innerHeight - rect.bottom < 200) {
|
||||
dropUp = true;
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user