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 })
+}