diff --git a/scripts/init.sh b/scripts/init.sh new file mode 100755 index 0000000..cdda7e7 --- /dev/null +++ b/scripts/init.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +files=`find .drone.yml api src -type f -name "config*" -or -name "*drone*"` + +grep -E "__.*__" $files | grep -v TIMESTAMP \ No newline at end of file diff --git a/src/api.ts b/src/api.ts new file mode 100644 index 0000000..cd17de7 --- /dev/null +++ b/src/api.ts @@ -0,0 +1,165 @@ +import { apiBaseURL } from "./config" +import * as sentry from "./sentry" +import * as SSR from "../api/hooks/lib/utils.js" + +// [MIT License](LICENSE.md) © [Jason Miller](https://jasonformat.com/) +const _f = function (url, options): Promise { + if (typeof XMLHttpRequest === "undefined") { + return Promise.resolve(null) + } + + options = options || {} + return new Promise((resolve, reject) => { + const request = new XMLHttpRequest() + const keys = [] + const all = [] + const headers = {} + + const response = (): Response => ({ + ok: ((request.status / 100) | 0) == 2, // 200-299 + statusText: request.statusText, + status: request.status, + url: request.responseURL, + text: () => Promise.resolve(request.responseText), + json: () => Promise.resolve(request.responseText).then(JSON.parse), + blob: () => Promise.resolve(new Blob([request.response])), + clone: response, + headers: { + // @ts-ignore + keys: () => keys, + // @ts-ignore + entries: () => all, + get: (n) => headers[n.toLowerCase()], + has: (n) => n.toLowerCase() in headers, + }, + }) + + request.open(options.method || "get", url, true) + + request.onload = () => { + request + .getAllResponseHeaders() + // @ts-ignore + .replace(/^(.*?):[^\S\n]*([\s\S]*?)$/gm, (m, key, value) => { + keys.push((key = key.toLowerCase())) + all.push([key, value]) + headers[key] = headers[key] + ? `${headers[key]},${value}` + : value + }) + resolve(response()) + } + + request.onerror = reject + + request.withCredentials = options.credentials == "include" + + for (const i in options.headers) { + request.setRequestHeader(i, options.headers[i]) + } + + request.send(options.body || null) + }) +} + +const _fetch = + typeof fetch === "undefined" + ? typeof window === "undefined" + ? _f + : window.fetch || _f + : fetch + +export const api = async ( + endpoint: string, + options?: { + method?: string + filter?: any + sort?: string + limit?: number + offset?: number + projection?: string + headers?: { + [key: string]: string + } + params?: { + [key: string]: string + } + } +): Promise<{ data: T; count: number }> => { + if (typeof window === "undefined") { + // ssr + // @ts-ignore + return context.ssrFetch(endpoint, options) + } + + // try ssr cache + const key = SSR.obj2str({ endpoint, options }) + // @ts-ignore + if (window.__SSR_CACHE__) { + // @ts-ignore + const ssrVal = window.__SSR_CACHE__[key] + console.log("SSR:", key, ssrVal) + if (ssrVal) { + return ssrVal + } + } + + let method = "GET" + + let query = "&count=1" + if (options?.filter) + query += "&filter=" + encodeURIComponent(JSON.stringify(options.filter)) + if (options?.sort) query += "&sort=" + options.sort + "&sort=_id" + if (options?.limit) query += "&limit=" + options.limit + if (options?.offset) query += "&offset=" + options.offset + if (options?.projection) query += "&projection=" + options.projection + + if (options?.params) { + Object.keys(options.params).forEach((p) => { + query += "&" + p + "=" + encodeURIComponent(options.params[p]) + }) + } + + let headers: any = { + "Content-Type": "application/json", + } + + if (options?.headers) headers = { ...headers, ...options.headers } + + let url = apiBaseURL + endpoint + (query ? "?" + query : "") + + const span = sentry.currentTransaction()?.startChild({ + op: "fetch", + description: method + " " + url, + data: Object.assign({}, options, { url }), + }) + const trace_id = span?.toTraceparent() + if (trace_id) { + headers["sentry-trace"] = trace_id + } + + const response = await _fetch(url, { + method, + mode: "cors", + headers, + }) + + span?.finish() + + // @ts-ignore + let data = (await response?.json()) || null + + if (response?.status < 200 || response?.status >= 400) + throw { response, data } + + // @ts-ignore + return { data, count: response?.headers?.get("x-results-count") || 0 } +} + +export const getContent = async (path: string): Promise => { + const c = await api("content", { limit: 1, filter: { path } }) + if (c?.data?.length) { + return c.data[0] + } + return null +} diff --git a/src/components/App.svelte b/src/components/App.svelte index 212fa16..e3f7284 100644 --- a/src/components/App.svelte +++ b/src/components/App.svelte @@ -1,5 +1,17 @@

__PROJECT_TITLE__

+
+ 1 + 2 + 3 + 4 + + + + + +
+ diff --git a/src/components/ContentBlocks.svelte b/src/components/ContentBlocks.svelte new file mode 100644 index 0000000..e58bd74 --- /dev/null +++ b/src/components/ContentBlocks.svelte @@ -0,0 +1,105 @@ +{#if blocks?.length} +
+
+ {#each blocks as box, idx} + +
+ {#if box.images?.length && (box.layout == 1 || box.layout == 3)} +
+ {box.images[0].label || ''} +
+ {/if} + {#if box.text || box.title || (box.button_text && box.button_url)} +
+ {#if box.subtitle} +
{box.subtitle}
+ {/if} + {#if box.title} + {#if accordeon == true} +

+ {box.title} + \/ +

+ {:else} +

{box.title}

+ {/if} + {/if} +
+ {@html box.text} + {#if box.button_text && box.button_url} + {box.button_text} + {/if} +
+
+ {/if} + {#if box.images?.length && (box.layout == 2 || box.layout == 4)} +
+ {box.images[0].label || ''} +
+ {/if} +
+ {/each} +
+
+{/if} + + + +