diff --git a/rest-api/db/migrations/20240719071602_main_tables.sql b/rest-api/db/migrations/20240719071602_main_tables.sql index 8d7de5c..2c023ab 100644 --- a/rest-api/db/migrations/20240719071602_main_tables.sql +++ b/rest-api/db/migrations/20240719071602_main_tables.sql @@ -53,8 +53,10 @@ CREATE TABLE internal.media ( CREATE TABLE internal.settings ( website_id UUID PRIMARY KEY REFERENCES internal.website (id) ON DELETE CASCADE, - accent_color_light_theme CHAR(7) CHECK (accent_color_light_theme ~ '^#[a-fA-F0-9]{6}$') NOT NULL DEFAULT '#a5d8ff', - accent_color_dark_theme CHAR(7) CHECK (accent_color_dark_theme ~ '^#[a-fA-F0-9]{6}$') NOT NULL DEFAULT '#114678', + accent_color_dark_theme CHAR(7) CHECK (accent_color_light_theme ~ '^#[a-fA-F0-9]{6}$') NOT NULL DEFAULT '#a5d8ff', + accent_color_light_theme CHAR(7) CHECK (accent_color_dark_theme ~ '^#[a-fA-F0-9]{6}$') NOT NULL DEFAULT '#114678', + background_color_dark_theme CHAR(7) CHECK (accent_color_light_theme ~ '^#[a-fA-F0-9]{6}$') NOT NULL DEFAULT '#262626', + background_color_light_theme CHAR(7) CHECK (accent_color_dark_theme ~ '^#[a-fA-F0-9]{6}$') NOT NULL DEFAULT '#ffffff', favicon_image UUID REFERENCES internal.media (id) ON DELETE SET NULL, last_modified_at TIMESTAMPTZ NOT NULL DEFAULT CLOCK_TIMESTAMP(), last_modified_by UUID REFERENCES internal.user (id) ON DELETE SET NULL diff --git a/rest-api/db/migrations/20240720132802_exposed_views_functions.sql b/rest-api/db/migrations/20240720132802_exposed_views_functions.sql index 89c0f3e..0e7e4aa 100644 --- a/rest-api/db/migrations/20240720132802_exposed_views_functions.sql +++ b/rest-api/db/migrations/20240720132802_exposed_views_functions.sql @@ -131,7 +131,7 @@ GRANT SELECT, UPDATE (title, is_published), DELETE ON internal.website TO authen GRANT SELECT, UPDATE, DELETE ON api.website TO authenticated_user; -GRANT SELECT, UPDATE (accent_color_light_theme, accent_color_dark_theme, favicon_image) ON internal.settings TO authenticated_user; +GRANT SELECT, UPDATE (accent_color_dark_theme, accent_color_light_theme, background_color_dark_theme, background_color_light_theme, favicon_image) ON internal.settings TO authenticated_user; GRANT SELECT, UPDATE ON api.settings TO authenticated_user; diff --git a/web-app/src/lib/components/MarkdownEditor.svelte b/web-app/src/lib/components/MarkdownEditor.svelte new file mode 100644 index 0000000..cbe47c6 --- /dev/null +++ b/web-app/src/lib/components/MarkdownEditor.svelte @@ -0,0 +1,72 @@ + + + diff --git a/web-app/src/lib/components/WebsiteEditor.svelte b/web-app/src/lib/components/WebsiteEditor.svelte index 0038b73..639cb06 100644 --- a/web-app/src/lib/components/WebsiteEditor.svelte +++ b/web-app/src/lib/components/WebsiteEditor.svelte @@ -2,30 +2,27 @@ import type { Snippet } from "svelte"; import { md } from "$lib/utils"; import { page } from "$app/stores"; + import { previewContent, textareaScrollTop } from "$lib/runes.svelte"; const { id, contentType, title, children, - fullPreview = false, - previewContent, - previewScrollTop = 0 + fullPreview = false }: { id: string; contentType: string; title: string; children: Snippet; fullPreview?: boolean; - previewContent: string; - previewScrollTop?: number; } = $props(); let previewElement: HTMLDivElement; $effect(() => { const scrollHeight = previewElement.scrollHeight - previewElement.clientHeight; - previewElement.scrollTop = (previewScrollTop / 100) * scrollHeight; + previewElement.scrollTop = (textareaScrollTop.value / 100) * scrollHeight; }); @@ -66,9 +63,9 @@
{#if fullPreview} - + {:else} - {@html md(previewContent, Object.keys($page.params).length > 1 ? true : false)} + {@html md(previewContent.value, Object.keys($page.params).length > 1 ? true : false)} {/if}
diff --git a/web-app/src/lib/db-schema.ts b/web-app/src/lib/db-schema.ts index 1706d8e..a02fb53 100644 --- a/web-app/src/lib/db-schema.ts +++ b/web-app/src/lib/db-schema.ts @@ -387,16 +387,20 @@ const media = { // Table settings export interface Settings { website_id: string; - accent_color_light_theme: string; accent_color_dark_theme: string; + accent_color_light_theme: string; + background_color_dark_theme: string; + background_color_light_theme: string; favicon_image: string | null; last_modified_at: Date; last_modified_by: string | null; } export interface SettingsInput { website_id: string; - accent_color_light_theme?: string; accent_color_dark_theme?: string; + accent_color_light_theme?: string; + background_color_dark_theme?: string; + background_color_light_theme?: string; favicon_image?: string | null; last_modified_at?: Date; last_modified_by?: string | null; @@ -405,8 +409,10 @@ const settings = { tableName: "settings", columns: [ "website_id", - "accent_color_light_theme", "accent_color_dark_theme", + "accent_color_light_theme", + "background_color_dark_theme", + "background_color_light_theme", "favicon_image", "last_modified_at", "last_modified_by" diff --git a/web-app/src/lib/runes.svelte.ts b/web-app/src/lib/runes.svelte.ts new file mode 100644 index 0000000..fab051e --- /dev/null +++ b/web-app/src/lib/runes.svelte.ts @@ -0,0 +1,30 @@ +let sendingState = $state(false); +let previewContentState = $state(""); +let textareaScrollTopState = $state(0); + +export const sending = { + get value() { + return sendingState; + }, + set value(val) { + sendingState = val; + } +}; + +export const previewContent = { + get value() { + return previewContentState; + }, + set value(val) { + previewContentState = val; + } +}; + +export const textareaScrollTop = { + get value() { + return textareaScrollTopState; + }, + set value(val) { + textareaScrollTopState = val; + } +}; diff --git a/web-app/src/lib/templates/common/Footer.svelte b/web-app/src/lib/templates/common/Footer.svelte index da65909..d18594d 100644 --- a/web-app/src/lib/templates/common/Footer.svelte +++ b/web-app/src/lib/templates/common/Footer.svelte @@ -1,5 +1,5 @@ -{#if sending} +{#if sending.value} {/if} -
{ - loadingDelay = window.setTimeout(() => (sending = true), 500); - return async ({ update }) => { - await update(); - window.clearTimeout(loadingDelay); - sending = false; - }; - }} -> +