forked from tsai/budibase
16 changed files with 221 additions and 97 deletions
@ -0,0 +1,78 @@ |
|||||
|
<script> |
||||
|
import { peekStore, dataSourceStore, routeStore } from "../store" |
||||
|
import { Modal, ModalContent, Button, Divider, Layout } from "@budibase/bbui" |
||||
|
import { onDestroy } from "svelte" |
||||
|
|
||||
|
let iframe |
||||
|
let fullscreen = false |
||||
|
|
||||
|
const invalidateDataSource = event => { |
||||
|
const { dataSourceId } = event.detail |
||||
|
dataSourceStore.actions.invalidateDataSource(dataSourceId) |
||||
|
} |
||||
|
|
||||
|
const handleCancel = () => { |
||||
|
iframe.contentWindow.removeEventListener( |
||||
|
"invalidate-datasource", |
||||
|
invalidateDataSource |
||||
|
) |
||||
|
peekStore.actions.hidePeek() |
||||
|
fullscreen = false |
||||
|
} |
||||
|
|
||||
|
const navigate = () => { |
||||
|
if ($peekStore.external) { |
||||
|
window.location = $peekStore.href |
||||
|
} else { |
||||
|
routeStore.actions.navigate($peekStore.url) |
||||
|
} |
||||
|
peekStore.actions.hidePeek() |
||||
|
} |
||||
|
|
||||
|
$: { |
||||
|
if (iframe) { |
||||
|
iframe.contentWindow.addEventListener( |
||||
|
"invalidate-datasource", |
||||
|
invalidateDataSource |
||||
|
) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
onDestroy(() => { |
||||
|
if (iframe) { |
||||
|
iframe.contentWindow.removeEventListener( |
||||
|
"invalidate-datasource", |
||||
|
invalidateDataSource |
||||
|
) |
||||
|
} |
||||
|
}) |
||||
|
</script> |
||||
|
|
||||
|
{#if $peekStore.showPeek} |
||||
|
<Modal fixed on:cancel={handleCancel}> |
||||
|
<ModalContent |
||||
|
cancelText="Close" |
||||
|
showConfirmButton={false} |
||||
|
size="XL" |
||||
|
title="Screen Peek" |
||||
|
showDivider={false} |
||||
|
> |
||||
|
<iframe title="Peek" bind:this={iframe} src={$peekStore.href} /> |
||||
|
<div slot="footer"> |
||||
|
<Button cta on:click={navigate}>Full screen</Button> |
||||
|
</div> |
||||
|
</ModalContent> |
||||
|
</Modal> |
||||
|
{/if} |
||||
|
|
||||
|
<style> |
||||
|
iframe { |
||||
|
margin: 0 -40px; |
||||
|
border: none; |
||||
|
border-bottom: 1px solid var(--spectrum-global-color-gray-300); |
||||
|
border-top: 1px solid var(--spectrum-global-color-gray-300); |
||||
|
width: calc(100% + 80px); |
||||
|
height: 640px; |
||||
|
transition: width 1s ease, height 1s ease, top 1s ease, left 1s ease; |
||||
|
} |
||||
|
</style> |
||||
@ -1,56 +1,50 @@ |
|||||
import { writable } from "svelte/store" |
import { writable, get } from "svelte/store" |
||||
|
import { generate } from "shortid" |
||||
|
|
||||
const NOTIFICATION_TIMEOUT = 3000 |
const NOTIFICATION_TIMEOUT = 3000 |
||||
|
|
||||
const createNotificationStore = () => { |
const createNotificationStore = () => { |
||||
const timeoutIds = new Set() |
let timeout |
||||
const _notifications = writable([], () => { |
let block = false |
||||
|
|
||||
|
const store = writable(null, () => { |
||||
return () => { |
return () => { |
||||
// clear all the timers
|
clearTimeout(timeout) |
||||
timeoutIds.forEach(timeoutId => { |
|
||||
clearTimeout(timeoutId) |
|
||||
}) |
|
||||
_notifications.set([]) |
|
||||
} |
} |
||||
}) |
}) |
||||
let block = false |
|
||||
|
|
||||
const blockNotifications = (timeout = 1000) => { |
const blockNotifications = (timeout = 1000) => { |
||||
block = true |
block = true |
||||
setTimeout(() => (block = false), timeout) |
setTimeout(() => (block = false), timeout) |
||||
} |
} |
||||
|
|
||||
const send = (message, type = "default") => { |
const send = (message, type = "info", icon) => { |
||||
if (block) { |
if (block) { |
||||
return |
return |
||||
} |
} |
||||
let _id = id() |
store.set({ |
||||
_notifications.update(state => { |
id: generate(), |
||||
return [...state, { id: _id, type, message }] |
type, |
||||
|
message, |
||||
|
icon, |
||||
|
delay: get(store) != null, |
||||
}) |
}) |
||||
const timeoutId = setTimeout(() => { |
clearTimeout(timeout) |
||||
_notifications.update(state => { |
timeout = setTimeout(() => { |
||||
return state.filter(({ id }) => id !== _id) |
store.set(null) |
||||
}) |
|
||||
}, NOTIFICATION_TIMEOUT) |
}, NOTIFICATION_TIMEOUT) |
||||
timeoutIds.add(timeoutId) |
|
||||
} |
} |
||||
|
|
||||
const { subscribe } = _notifications |
|
||||
|
|
||||
return { |
return { |
||||
subscribe, |
subscribe: store.subscribe, |
||||
send, |
actions: { |
||||
danger: msg => send(msg, "danger"), |
info: msg => send(msg, "info", "Info"), |
||||
warning: msg => send(msg, "warning"), |
success: msg => send(msg, "success", "CheckmarkCircle"), |
||||
info: msg => send(msg, "info"), |
warning: msg => send(msg, "warning", "Alert"), |
||||
success: msg => send(msg, "success"), |
error: msg => send(msg, "error", "Alert"), |
||||
blockNotifications, |
blockNotifications, |
||||
|
}, |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
function id() { |
|
||||
return "_" + Math.random().toString(36).substr(2, 9) |
|
||||
} |
|
||||
|
|
||||
export const notificationStore = createNotificationStore() |
export const notificationStore = createNotificationStore() |
||||
|
|||||
@ -0,0 +1,36 @@ |
|||||
|
import { writable } from "svelte/store" |
||||
|
|
||||
|
const initialState = { |
||||
|
showPeek: false, |
||||
|
url: null, |
||||
|
href: null, |
||||
|
external: false, |
||||
|
} |
||||
|
|
||||
|
const createPeekStore = () => { |
||||
|
const store = writable(initialState) |
||||
|
|
||||
|
const showPeek = url => { |
||||
|
let href = url |
||||
|
let external = !url.startsWith("/") |
||||
|
if (!external) { |
||||
|
href = `${window.location.href.split("#")[0]}#${url}?peek=true` |
||||
|
} |
||||
|
store.set({ |
||||
|
showPeek: true, |
||||
|
url, |
||||
|
href, |
||||
|
external, |
||||
|
}) |
||||
|
} |
||||
|
const hidePeek = () => { |
||||
|
store.set(initialState) |
||||
|
} |
||||
|
|
||||
|
return { |
||||
|
subscribe: store.subscribe, |
||||
|
actions: { showPeek, hidePeek }, |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export const peekStore = createPeekStore() |
||||
Loading…
Reference in new issue