zwischenstand
This commit is contained in:
@@ -5,7 +5,6 @@
|
|||||||
import Content from "./routes/Content.svelte"
|
import Content from "./routes/Content.svelte"
|
||||||
import Notifications from "./lib/components/widgets/Notifications.svelte"
|
import Notifications from "./lib/components/widgets/Notifications.svelte"
|
||||||
import SSRSkip from "./lib/components/SSRSkip.svelte"
|
import SSRSkip from "./lib/components/SSRSkip.svelte"
|
||||||
import DateModal from "./lib/components/widgets/DateModal.svelte"
|
|
||||||
import { baseURL } from "./config"
|
import { baseURL } from "./config"
|
||||||
import { isMobile, location, openModal } from "./lib/store"
|
import { isMobile, location, openModal } from "./lib/store"
|
||||||
|
|
||||||
@@ -106,7 +105,6 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Notifications />
|
<Notifications />
|
||||||
<DateModal />
|
|
||||||
<SSRSkip />
|
<SSRSkip />
|
||||||
|
|
||||||
<style lang="less" global>
|
<style lang="less" global>
|
||||||
|
|||||||
@@ -1,51 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import { actionApproval } from "../../store"
|
|
||||||
import Modal from "../Modal.svelte"
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{#if $actionApproval}
|
|
||||||
<Modal
|
|
||||||
show={true}
|
|
||||||
size="sm"
|
|
||||||
on:close={() => {
|
|
||||||
actionApproval.set(null)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<svelte:fragment slot="title">{$actionApproval.modalTitle}</svelte:fragment>
|
|
||||||
<p>
|
|
||||||
{$actionApproval.modalText}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div
|
|
||||||
slot="footer"
|
|
||||||
class="action-approval-footer"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="btn cta primary"
|
|
||||||
on:click={() => {
|
|
||||||
actionApproval.set(null)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Nein
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="btn cta secondary"
|
|
||||||
on:click={() => {
|
|
||||||
$actionApproval.callback()
|
|
||||||
actionApproval.set(null)
|
|
||||||
}}>Ja</button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<style lang="less">
|
|
||||||
.action-approval-footer {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
h2 {
|
|
||||||
color: var(--text-invers-100);
|
|
||||||
padding-bottom: 1px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
<script lang="ts"></script>
|
|
||||||
|
|
||||||
<div id="dateModal"></div>
|
|
||||||
|
|
||||||
<style
|
|
||||||
lang="less"
|
|
||||||
global
|
|
||||||
>
|
|
||||||
#dateModal {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 9999;
|
|
||||||
background-color: white;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#dateDeleteValidationModal {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 9999;
|
|
||||||
background-color: white;
|
|
||||||
display: none;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 10px;
|
|
||||||
padding: 12px;
|
|
||||||
width: 236px;
|
|
||||||
.question {
|
|
||||||
padding: 0px;
|
|
||||||
margin: 0px;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
.bottom {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
.cancel,
|
|
||||||
.delete {
|
|
||||||
padding: 0px;
|
|
||||||
|
|
||||||
cursor: pointer;
|
|
||||||
background-color: transparent;
|
|
||||||
border: none;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
.cancel {
|
|
||||||
color: var(--stategrey);
|
|
||||||
}
|
|
||||||
.delete {
|
|
||||||
color: var(--renzrot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
//check with matchMedia api if the slot should be rendered or not.
|
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
export let query: string
|
export let query: string
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
<script
|
<script module lang="ts">
|
||||||
context="module"
|
|
||||||
lang="ts"
|
|
||||||
>
|
|
||||||
import pDebounce from "p-debounce"
|
import pDebounce from "p-debounce"
|
||||||
import { getDBEntries, getDBEntry } from "../../../api"
|
|
||||||
|
|
||||||
// TODO: check ssr
|
|
||||||
|
|
||||||
|
import { apiBaseURL } from "../../configs/config"
|
||||||
|
import { getCachedEntries, getCachedEntry } from "../../api"
|
||||||
const medialibCache: { [id: string]: MedialibEntry } = {}
|
const medialibCache: { [id: string]: MedialibEntry } = {}
|
||||||
|
|
||||||
let loadQueue: string[] = []
|
let loadQueue: string[] = []
|
||||||
@@ -21,7 +17,7 @@
|
|||||||
if (loadQueue.length) {
|
if (loadQueue.length) {
|
||||||
const _ids = loadQueue
|
const _ids = loadQueue
|
||||||
loadQueue = []
|
loadQueue = []
|
||||||
const entries = await getDBEntries("medialib", { _id: { $in: _ids } })
|
const entries = await getCachedEntries("medialib", { _id: { $in: _ids } })
|
||||||
entries.forEach((entry) => {
|
entries.forEach((entry) => {
|
||||||
medialibCache[entry.id] = entry
|
medialibCache[entry.id] = entry
|
||||||
})
|
})
|
||||||
@@ -32,14 +28,24 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { apiBaseURL } from "../../../config"
|
let {
|
||||||
import { apiBaseOverride } from "../../store"
|
id,
|
||||||
|
noPlaceholder,
|
||||||
|
loading,
|
||||||
|
childrenSnippet,
|
||||||
|
loadingSnippet,
|
||||||
|
notFoundSnippet,
|
||||||
|
}: {
|
||||||
|
id: string
|
||||||
|
noPlaceholder?: boolean
|
||||||
|
loading?: boolean
|
||||||
|
loadingSnippet: ({ entry, src }: { entry: MedialibEntry; src: string }) => any
|
||||||
|
childrenSnippet: ({ entry, src }: { entry: MedialibEntry; src: string }) => any
|
||||||
|
notFoundSnippet: () => any
|
||||||
|
} = $props()
|
||||||
|
|
||||||
export let id: string,
|
let entry: MedialibEntry = $state(),
|
||||||
noPlaceholder: boolean = false,
|
fileSrc: string = $state()
|
||||||
loading = true
|
|
||||||
|
|
||||||
let entry: MedialibEntry, fileSrc: string
|
|
||||||
|
|
||||||
async function loadFile() {
|
async function loadFile() {
|
||||||
loading = true
|
loading = true
|
||||||
@@ -47,33 +53,31 @@
|
|||||||
fileSrc = null
|
fileSrc = null
|
||||||
try {
|
try {
|
||||||
entry =
|
entry =
|
||||||
typeof window !== "undefined" ? await loadMedialibEntry(id) : await getDBEntry("medialib", { _id: id })
|
typeof window !== "undefined"
|
||||||
if (entry?.file?.src)
|
? await loadMedialibEntry(id)
|
||||||
fileSrc = ($apiBaseOverride ? $apiBaseOverride : apiBaseURL) + "medialib/" + id + "/" + entry.file.src
|
: await getCachedEntry("medialib", { _id: id })
|
||||||
|
if (entry?.file?.src) {
|
||||||
|
fileSrc = `${apiBaseURL}${window?.location.host.includes("tibi") ? "_/renz_shop_2024/" : ""}medialib/${id}/${entry.file.src}`
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
}
|
}
|
||||||
loading = false
|
loading = false
|
||||||
}
|
}
|
||||||
|
|
||||||
$: if (id) loadFile()
|
$effect(() => {
|
||||||
|
if (id) loadFile()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if id}
|
{#if id}
|
||||||
{#if loading}
|
{#if loading}
|
||||||
{#if !noPlaceholder}
|
{#if !noPlaceholder}
|
||||||
<slot
|
{@render loadingSnippet({ entry, src: fileSrc })}
|
||||||
name="loading"
|
|
||||||
entry={entry}
|
|
||||||
src={fileSrc}
|
|
||||||
/>
|
|
||||||
{/if}
|
{/if}
|
||||||
{:else if entry}
|
{:else if entry}
|
||||||
<slot
|
{@render childrenSnippet({ entry, src: fileSrc })}
|
||||||
entry={entry}
|
|
||||||
src={fileSrc}
|
|
||||||
/>
|
|
||||||
{:else if !noPlaceholder}
|
{:else if !noPlaceholder}
|
||||||
<slot name="not-found" />
|
{@render notFoundSnippet()}
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -1,83 +1,138 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { onDestroy } from "svelte"
|
||||||
import MedialibFile from "./MedialibFile.svelte"
|
import MedialibFile from "./MedialibFile.svelte"
|
||||||
|
|
||||||
export let id: string,
|
interface Props {
|
||||||
filter: null | "xs" | "s" | "m" | "l" | "xl" | "xxl" = null,
|
id: string
|
||||||
minWidth: number = null,
|
filter?:
|
||||||
noPlaceholder: boolean = false
|
| null
|
||||||
|
| "xs"
|
||||||
|
| "s"
|
||||||
|
| "m"
|
||||||
|
| "l"
|
||||||
|
| "xl"
|
||||||
|
| "xxl"
|
||||||
|
| "xs-webp"
|
||||||
|
| "s-webp"
|
||||||
|
| "m-webp"
|
||||||
|
| "l-webp"
|
||||||
|
| "xl-webp"
|
||||||
|
| "xxl-webp"
|
||||||
|
minWidth?: number
|
||||||
|
noPlaceholder?: boolean
|
||||||
|
style?: string
|
||||||
|
widthMultiplier?: number
|
||||||
|
lazy?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
let imgElement: HTMLImageElement
|
let {
|
||||||
|
id,
|
||||||
|
filter,
|
||||||
|
minWidth = null,
|
||||||
|
noPlaceholder = false,
|
||||||
|
style,
|
||||||
|
widthMultiplier = 1,
|
||||||
|
lazy = false,
|
||||||
|
}: Props = $props()
|
||||||
|
|
||||||
|
let imgElement: HTMLImageElement = $state()
|
||||||
|
|
||||||
function getSrcWithFilter(_imgElement: HTMLImageElement, entry: MedialibEntry, src: string) {
|
function getSrcWithFilter(_imgElement: HTMLImageElement, entry: MedialibEntry, src: string) {
|
||||||
if (typeof window === "undefined") {
|
if (typeof window === "undefined") {
|
||||||
return src + `?filter=${filter || "xs"}`
|
return src + `?filter=${filter || "xs-webp"}`
|
||||||
}
|
}
|
||||||
|
let internalFilter = filter
|
||||||
if (imgElement) {
|
if (imgElement) {
|
||||||
if (!entry.file?.type?.match(/^image\/(png|jpe?g)/)) return src // no filter for svg
|
if (!entry.file?.type?.match(/^image\/(png|jpe?g|webp)/)) return src // no filter for svg
|
||||||
if (!filter) {
|
if (!internalFilter) {
|
||||||
|
let imgWidth = _imgElement.width
|
||||||
|
|
||||||
|
if (widthMultiplier) {
|
||||||
|
imgWidth *= widthMultiplier
|
||||||
|
}
|
||||||
|
|
||||||
// get the width of the image element
|
// get the width of the image element
|
||||||
const width = minWidth
|
const width = minWidth ? (imgWidth < minWidth ? minWidth : imgWidth) : imgWidth
|
||||||
? _imgElement.width < minWidth
|
|
||||||
? minWidth
|
|
||||||
: _imgElement.width
|
|
||||||
: _imgElement.width
|
|
||||||
switch (true) {
|
switch (true) {
|
||||||
case width <= 90:
|
case width <= 90:
|
||||||
filter = "xs"
|
internalFilter = "xs-webp"
|
||||||
break
|
break
|
||||||
case width <= 300:
|
case width <= 300:
|
||||||
filter = "s"
|
internalFilter = "s-webp"
|
||||||
break
|
break
|
||||||
case width <= 600:
|
case width <= 600:
|
||||||
filter = "m"
|
internalFilter = "m-webp"
|
||||||
break
|
break
|
||||||
case width <= 1200:
|
case width <= 1200:
|
||||||
filter = "l"
|
internalFilter = "l-webp"
|
||||||
break
|
break
|
||||||
case width <= 2000:
|
case width <= 2000:
|
||||||
filter = "xl"
|
internalFilter = "xl-webp"
|
||||||
break
|
break
|
||||||
case width <= 4000:
|
case width <= 4000:
|
||||||
filter = "xxl"
|
internalFilter = "xxl-webp"
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return src + (filter ? `?filter=${filter}` : "")
|
return src + (internalFilter ? `?filter=${internalFilter}` : "")
|
||||||
} else {
|
} else {
|
||||||
// placeholder
|
// placeholder
|
||||||
return "/assets/img/placeholder-image.png"
|
return "/assets/img/placeholder-image.png"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let resizeObserver: ResizeObserver
|
||||||
|
|
||||||
|
function initResizeObserver(node: HTMLImageElement, { entry, src }: { entry: MedialibEntry; src: string }) {
|
||||||
|
if (!filter && typeof ResizeObserver !== "undefined") {
|
||||||
|
resizeObserver?.disconnect()
|
||||||
|
resizeObserver = new ResizeObserver(() => {
|
||||||
|
const oldWidth = parseInt(node.getAttribute("data-width")) || 0
|
||||||
|
const newWidth = node.width
|
||||||
|
|
||||||
|
if (oldWidth >= newWidth) return
|
||||||
|
|
||||||
|
const newSrc = getSrcWithFilter(imgElement, entry, src)
|
||||||
|
if (newSrc !== node.getAttribute("src")) {
|
||||||
|
node.setAttribute("src", newSrc)
|
||||||
|
}
|
||||||
|
node.setAttribute("data-width", newWidth.toString())
|
||||||
|
})
|
||||||
|
resizeObserver.observe(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
destroy() {
|
||||||
|
resizeObserver?.disconnect()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
|
resizeObserver?.disconnect()
|
||||||
|
})
|
||||||
|
let properties = {}
|
||||||
|
if (lazy) {
|
||||||
|
properties = { loading: "lazy" }
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if id}
|
{#if id}
|
||||||
<MedialibFile
|
<MedialibFile {id} {noPlaceholder}>
|
||||||
id={id}
|
{#snippet childrenSnippet({ entry, src }: { entry: MedialibEntry; src: string })}
|
||||||
let:entry
|
|
||||||
let:src
|
|
||||||
noPlaceholder={noPlaceholder}
|
|
||||||
>
|
|
||||||
<img
|
<img
|
||||||
|
{style}
|
||||||
bind:this={imgElement}
|
bind:this={imgElement}
|
||||||
src={getSrcWithFilter(imgElement, entry, src)}
|
src={getSrcWithFilter(imgElement, entry, src)}
|
||||||
alt={entry.alt || 'icon'}
|
alt={entry.alt || "icon"}
|
||||||
data-entry-id={id}
|
|
||||||
/>
|
|
||||||
<img
|
|
||||||
slot="loading"
|
|
||||||
let:entry
|
|
||||||
let:src
|
|
||||||
src="/assets/img/placeholder-image.png"
|
|
||||||
alt="placeholder"
|
|
||||||
data-entry-id={id}
|
|
||||||
data-entry={JSON.stringify(entry)}
|
|
||||||
data-entry-src={src}
|
|
||||||
/>
|
|
||||||
<img
|
|
||||||
slot="not-found"
|
|
||||||
src="/assets/img/placeholder-image.png"
|
|
||||||
alt="not found"
|
|
||||||
data-entry-id={id}
|
data-entry-id={id}
|
||||||
|
use:initResizeObserver={{ entry, src }}
|
||||||
|
loading="lazy"
|
||||||
|
{...properties}
|
||||||
/>
|
/>
|
||||||
|
{/snippet}
|
||||||
|
{#snippet loadingSnippet({ entry, src }: { entry: MedialibEntry; src: string })}{/snippet}
|
||||||
|
|
||||||
|
{#snippet notFoundSnippet()}{/snippet}
|
||||||
</MedialibFile>
|
</MedialibFile>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
class="container"
|
class="container"
|
||||||
class:inModal={force}
|
class:inModal={force}
|
||||||
>
|
>
|
||||||
{#each $notifications as n, i (n)}
|
{#each $notifications as n (n)}
|
||||||
{#if !$openModal || ($openModal && force)}
|
{#if !$openModal || ($openModal && force)}
|
||||||
<!-- svelte-ignore a11y-no-noninteractive-element-to-interactive-role -->
|
<!-- svelte-ignore a11y-no-noninteractive-element-to-interactive-role -->
|
||||||
<li
|
<li
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
import { getCachedEntry } from "../api"
|
import { getCachedEntry } from "../api"
|
||||||
import NotFound from "./NotFound.svelte"
|
import NotFound from "./NotFound.svelte"
|
||||||
|
|
||||||
export let location: LocationStore | undefined
|
export let location: LocationStore | undefined = undefined
|
||||||
export let id: string | undefined
|
export let id: string | null = null
|
||||||
|
|
||||||
let loading = true
|
let loading = true
|
||||||
let contentEntry: ContentEntry | null = null
|
let contentEntry: ContentEntry | null = null
|
||||||
|
|||||||
Reference in New Issue
Block a user