diff --git a/dev/prod/public/config-dev.json b/dev/prod/public/config-dev.json index 3c1e0cdca7b..2a4256cee51 100644 --- a/dev/prod/public/config-dev.json +++ b/dev/prod/public/config-dev.json @@ -1,6 +1,7 @@ { "ACCOUNTS_URL":"https://account.hc.engineering", - "UPLOAD_URL":"/files", + "UPLOAD_URL": "https://datalake.hc.engineering/upload/form-data/:workspace", + "FILES_URL": "https://datalake.hc.engineering/blob/:workspace/:blobId/:filename", "MODEL_VERSION": null, "TELEGRAM_URL": "https://telegram.hc.engineering", "GMAIL_URL": "https://gmail.hc.engineering", @@ -11,5 +12,7 @@ "PRESENCE_URL": "wss://presence.hc.engineering", "PUBLIC_SCHEDULE_URL": "https://schedule.hc.engineering", "CALDAV_SERVER_URL": "https://caldav.hc.engineering", - "BACKUP_URL": "https://front.hc.engineering/api/backup" + "BACKUP_URL": "https://front.hc.engineering/api/backup", + "PREVIEW_CONFIG": "image|https://datalake.hc.engineering/image/fit=scale-down,width=:width,height=:height,dpr=:dpr/:workspace/:blobId;video|https://datalake.hc.engineering/video/:workspace/:blobId/meta", + "COMMUNICATION_API_ENABLED": "true" } \ No newline at end of file diff --git a/packages/presentation/src/components/Image.svelte b/packages/presentation/src/components/Image.svelte index 98a8b09785b..41f77e93fa0 100644 --- a/packages/presentation/src/components/Image.svelte +++ b/packages/presentation/src/components/Image.svelte @@ -14,7 +14,9 @@ --> - +
+ +
diff --git a/packages/ui/src/lazy.ts b/packages/ui/src/lazy.ts index 4fcdcd94804..e707ddd548c 100644 --- a/packages/ui/src/lazy.ts +++ b/packages/ui/src/lazy.ts @@ -1,11 +1,20 @@ import { DelayedCaller } from './utils' +type ObserverMode = 'once' | 'continuous' + +interface ObserverEntry { + callback: (isIntersecting: boolean) => void + mode: ObserverMode +} + const observers = new Map() -const entryMap = new WeakMap void }>() +const entryMap = new WeakMap() const delayedCaller = new DelayedCaller(5) + function makeObserver (rootMargin: string): IntersectionObserver { const entriesPending = new Map() + const notifyObservers = (observer: IntersectionObserver): void => { for (const [target, entry] of entriesPending.entries()) { const entryData = entryMap.get(target) @@ -15,13 +24,16 @@ function makeObserver (rootMargin: string): IntersectionObserver { } entryData.callback(entry.isIntersecting) - if (entry.isIntersecting) { + + // Only unobserve if mode is 'once' and element became visible + if (entry.isIntersecting && entryData.mode === 'once') { entryMap.delete(target) observer.unobserve(target) } } entriesPending.clear() } + const observer = new IntersectionObserver( (entries, observer) => { for (const entry of entries) { @@ -36,15 +48,21 @@ function makeObserver (rootMargin: string): IntersectionObserver { return observer } -function listen (rootMargin: string, element: Element, callback: (isIntersecting: boolean) => void): () => void { +function listen ( + rootMargin: string, + element: Element, + callback: (isIntersecting: boolean) => void, + mode: ObserverMode = 'once' +): () => void { let observer = observers.get(rootMargin) if (observer == null) { observer = makeObserver(rootMargin) observers.set(rootMargin, observer) } - entryMap.set(element, { callback }) + entryMap.set(element, { callback, mode }) observer.observe(element) + return () => { observer?.unobserve(element) entryMap.delete(element) @@ -56,33 +74,73 @@ function listen (rootMargin: string, element: Element, callback: (isIntersecting */ export const isLazyEnabled = (): boolean => (localStorage.getItem('#platform.lazy.loading') ?? 'true') === 'true' -export function lazyObserver (node: Element, onVisible: (value: boolean, unsubscribe?: () => void) => void): any { +interface LazyObserverOptions { + mode?: ObserverMode + rootMargin?: string +} + +export function lazyObserver ( + node: Element, + onVisible: (value: boolean, unsubscribe?: () => void) => void, + options: LazyObserverOptions = {} +): any { + const { mode = 'once', rootMargin = '20%' } = options + let visible = false + let destroy = (): void => {} + const lazyEnabled = isLazyEnabled() - if (!lazyEnabled) { + + // Special case: 'once' mode with lazy disabled - immediately report visible + if (!lazyEnabled && mode === 'once') { visible = true onVisible(visible) + return { + destroy: () => {}, + update: () => {} + } } - if (visible) { - onVisible(visible) - return {} + + // For continuous mode, we set up once and don't need the update logic + if (mode === 'continuous') { + destroy = listen( + rootMargin, + node, + (isIntersecting) => { + if (visible !== isIntersecting) { + visible = isIntersecting + onVisible(visible, destroy) + } + }, + mode + ) + + return { + destroy, + update: () => {} // No-op for continuous mode + } } + // For 'once' mode with lazy enabled let needsUpdate = true - let destroy = (): void => {} - // we need this update function to re-trigger observer for moved elements - // moved elements are relevant because onVisible can have side effects + const update = (): void => { if (!needsUpdate) { return } needsUpdate = false destroy() - destroy = listen('20%', node, (isIntersecting) => { - visible = isIntersecting - needsUpdate = visible - onVisible(visible, destroy) - }) + + destroy = listen( + rootMargin, + node, + (isIntersecting) => { + visible = isIntersecting + needsUpdate = visible + onVisible(visible, destroy) + }, + mode + ) } update() @@ -91,3 +149,19 @@ export function lazyObserver (node: Element, onVisible: (value: boolean, unsubsc update } } + +export function lazyObserverOnce ( + node: Element, + onVisible: (value: boolean, unsubscribe?: () => void) => void, + rootMargin = '20%' +): any { + return lazyObserver(node, onVisible, { mode: 'once', rootMargin }) +} + +export function lazyObserverContinuous ( + node: Element, + onVisible: (value: boolean, unsubscribe?: () => void) => void, + rootMargin = '20%' +): any { + return lazyObserver(node, onVisible, { mode: 'continuous', rootMargin }) +}