mirror of
https://github.com/thiloho/archtika.git
synced 2025-11-22 10:51:36 +01:00
Refactor web app code and add background color setting
This commit is contained in:
@@ -6,16 +6,15 @@
|
||||
import SuccessOrError from "$lib/components/SuccessOrError.svelte";
|
||||
import type { ActionData, PageServerData } from "./$types";
|
||||
import LoadingSpinner from "$lib/components/LoadingSpinner.svelte";
|
||||
import { enhanceForm } from "$lib/utils";
|
||||
import { sending } from "$lib/runes.svelte";
|
||||
|
||||
const { form, data }: { form: ActionData; data: PageServerData } = $props();
|
||||
|
||||
let sending = $state(false);
|
||||
let loadingDelay: number;
|
||||
</script>
|
||||
|
||||
<SuccessOrError success={form?.success} message={form?.message} />
|
||||
|
||||
{#if sending}
|
||||
{#if sending.value}
|
||||
<LoadingSpinner />
|
||||
{/if}
|
||||
|
||||
@@ -27,19 +26,7 @@
|
||||
<Modal id="create-website" text="Create website">
|
||||
<h3>Create website</h3>
|
||||
|
||||
<form
|
||||
method="POST"
|
||||
action="?/createWebsite"
|
||||
use:enhance={() => {
|
||||
loadingDelay = window.setTimeout(() => (sending = true), 500);
|
||||
return async ({ update }) => {
|
||||
await update();
|
||||
window.clearTimeout(loadingDelay);
|
||||
window.location.hash = "!";
|
||||
sending = false;
|
||||
};
|
||||
}}
|
||||
>
|
||||
<form method="POST" action="?/createWebsite" use:enhance={enhanceForm({ closeModal: true })}>
|
||||
<label>
|
||||
Type:
|
||||
<select name="content-type">
|
||||
@@ -121,15 +108,7 @@
|
||||
<form
|
||||
method="POST"
|
||||
action="?/updateWebsite"
|
||||
use:enhance={() => {
|
||||
loadingDelay = window.setTimeout(() => (sending = true), 500);
|
||||
return async ({ update }) => {
|
||||
await update({ reset: false });
|
||||
window.clearTimeout(loadingDelay);
|
||||
window.location.hash = "!";
|
||||
sending = false;
|
||||
};
|
||||
}}
|
||||
use:enhance={enhanceForm({ reset: false, closeModal: true })}
|
||||
>
|
||||
<input type="hidden" name="id" value={id} />
|
||||
<label>
|
||||
@@ -157,15 +136,7 @@
|
||||
<form
|
||||
method="POST"
|
||||
action="?/deleteWebsite"
|
||||
use:enhance={() => {
|
||||
loadingDelay = window.setTimeout(() => (sending = true), 500);
|
||||
return async ({ update }) => {
|
||||
await update();
|
||||
window.clearTimeout(loadingDelay);
|
||||
window.location.hash = "!";
|
||||
sending = false;
|
||||
};
|
||||
}}
|
||||
use:enhance={enhanceForm({ closeModal: true })}
|
||||
>
|
||||
<input type="hidden" name="id" value={id} />
|
||||
|
||||
|
||||
@@ -4,16 +4,15 @@
|
||||
import SuccessOrError from "$lib/components/SuccessOrError.svelte";
|
||||
import LoadingSpinner from "$lib/components/LoadingSpinner.svelte";
|
||||
import type { ActionData, PageServerData } from "./$types";
|
||||
import { enhanceForm } from "$lib/utils";
|
||||
import { sending } from "$lib/runes.svelte";
|
||||
|
||||
const { data, form }: { data: PageServerData; form: ActionData } = $props();
|
||||
|
||||
let sending = $state(false);
|
||||
let loadingDelay: number;
|
||||
</script>
|
||||
|
||||
<SuccessOrError success={form?.success} message={form?.message} />
|
||||
|
||||
{#if sending}
|
||||
{#if sending.value}
|
||||
<LoadingSpinner />
|
||||
{/if}
|
||||
|
||||
@@ -39,18 +38,7 @@
|
||||
<a href="#logout">Logout</a>
|
||||
</h2>
|
||||
|
||||
<form
|
||||
method="POST"
|
||||
action="?/logout"
|
||||
use:enhance={() => {
|
||||
loadingDelay = window.setTimeout(() => (sending = true), 500);
|
||||
return async ({ update }) => {
|
||||
await update();
|
||||
window.clearTimeout(loadingDelay);
|
||||
sending = false;
|
||||
};
|
||||
}}
|
||||
>
|
||||
<form method="POST" action="?/logout" use:enhance={enhanceForm()}>
|
||||
<button type="submit">Logout</button>
|
||||
</form>
|
||||
</section>
|
||||
@@ -68,19 +56,7 @@
|
||||
Deleting your account will irretrievably erase all data.
|
||||
</p>
|
||||
|
||||
<form
|
||||
method="POST"
|
||||
action="?/deleteAccount"
|
||||
use:enhance={() => {
|
||||
loadingDelay = window.setTimeout(() => (sending = true), 500);
|
||||
return async ({ update }) => {
|
||||
await update();
|
||||
window.clearTimeout(loadingDelay);
|
||||
window.location.hash = "!";
|
||||
sending = false;
|
||||
};
|
||||
}}
|
||||
>
|
||||
<form method="POST" action="?/deleteAccount" use:enhance={enhanceForm({ closeModal: true })}>
|
||||
<label>
|
||||
Password:
|
||||
<input type="password" name="password" required />
|
||||
|
||||
@@ -76,8 +76,10 @@ export const actions: Actions = {
|
||||
"PATCH",
|
||||
{
|
||||
body: {
|
||||
accent_color_light_theme: data.get("accent-color-light"),
|
||||
accent_color_dark_theme: data.get("accent-color-dark"),
|
||||
accent_color_light_theme: data.get("accent-color-light"),
|
||||
background_color_dark_theme: data.get("background-color-dark"),
|
||||
background_color_light_theme: data.get("background-color-light"),
|
||||
favicon_image: uploadedImage.data?.file_id
|
||||
},
|
||||
successMessage: "Successfully updated global settings"
|
||||
|
||||
@@ -1,38 +1,24 @@
|
||||
<script lang="ts">
|
||||
import { enhance } from "$app/forms";
|
||||
import WebsiteEditor from "$lib/components/WebsiteEditor.svelte";
|
||||
import { ALLOWED_MIME_TYPES, handleImagePaste } from "$lib/utils";
|
||||
import { ALLOWED_MIME_TYPES } from "$lib/utils";
|
||||
import SuccessOrError from "$lib/components/SuccessOrError.svelte";
|
||||
import type { ActionData, LayoutServerData, PageServerData } from "./$types";
|
||||
import Modal from "$lib/components/Modal.svelte";
|
||||
import LoadingSpinner from "$lib/components/LoadingSpinner.svelte";
|
||||
import { enhanceForm } from "$lib/utils";
|
||||
import { sending } from "$lib/runes.svelte";
|
||||
import MarkdownEditor from "$lib/components/MarkdownEditor.svelte";
|
||||
import { previewContent } from "$lib/runes.svelte";
|
||||
|
||||
const { data, form }: { data: PageServerData & LayoutServerData; form: ActionData } = $props();
|
||||
|
||||
let previewContent = $state(data.home.main_content);
|
||||
let mainContentTextarea: HTMLTextAreaElement;
|
||||
let textareaScrollTop = $state(0);
|
||||
|
||||
const updateScrollPercentage = () => {
|
||||
const { scrollTop, scrollHeight, clientHeight } = mainContentTextarea;
|
||||
textareaScrollTop = (scrollTop / (scrollHeight - clientHeight)) * 100;
|
||||
};
|
||||
|
||||
const handlePaste = async (event: ClipboardEvent) => {
|
||||
const newContent = await handleImagePaste(event, data.API_BASE_PREFIX);
|
||||
|
||||
if (newContent) {
|
||||
previewContent = newContent;
|
||||
}
|
||||
};
|
||||
|
||||
let sending = $state(false);
|
||||
let loadingDelay: number;
|
||||
previewContent.value = data.home.main_content;
|
||||
</script>
|
||||
|
||||
<SuccessOrError success={form?.success} message={form?.message} />
|
||||
|
||||
{#if sending}
|
||||
{#if sending.value}
|
||||
<LoadingSpinner />
|
||||
{/if}
|
||||
|
||||
@@ -40,9 +26,6 @@
|
||||
id={data.website.id}
|
||||
contentType={data.website.content_type}
|
||||
title={data.website.title}
|
||||
previewContent={previewContent ||
|
||||
"Put some markdown content in main content to see a live preview here"}
|
||||
previewScrollTop={textareaScrollTop}
|
||||
>
|
||||
<section id="global">
|
||||
<h2>
|
||||
@@ -52,27 +35,30 @@
|
||||
action="?/updateGlobal"
|
||||
method="POST"
|
||||
enctype="multipart/form-data"
|
||||
use:enhance={() => {
|
||||
loadingDelay = window.setTimeout(() => (sending = true), 500);
|
||||
return async ({ update }) => {
|
||||
await update({ reset: false });
|
||||
window.clearTimeout(loadingDelay);
|
||||
sending = false;
|
||||
};
|
||||
}}
|
||||
use:enhance={enhanceForm({ reset: false })}
|
||||
>
|
||||
<label>
|
||||
Light accent color:
|
||||
Background color dark theme:
|
||||
<input
|
||||
type="color"
|
||||
name="accent-color-light"
|
||||
value={data.globalSettings.accent_color_light_theme}
|
||||
name="background-color-dark"
|
||||
value={data.globalSettings.background_color_dark_theme}
|
||||
pattern="\S(.*\S)?"
|
||||
required
|
||||
/>
|
||||
</label>
|
||||
<label>
|
||||
Dark accent color:
|
||||
Background color light theme:
|
||||
<input
|
||||
type="color"
|
||||
name="background-color-light"
|
||||
value={data.globalSettings.background_color_light_theme}
|
||||
pattern="\S(.*\S)?"
|
||||
required
|
||||
/>
|
||||
</label>
|
||||
<label>
|
||||
Accent color dark theme:
|
||||
<input
|
||||
type="color"
|
||||
name="accent-color-dark"
|
||||
@@ -81,6 +67,16 @@
|
||||
required
|
||||
/>
|
||||
</label>
|
||||
<label>
|
||||
Accent color light theme:
|
||||
<input
|
||||
type="color"
|
||||
name="accent-color-light"
|
||||
value={data.globalSettings.accent_color_light_theme}
|
||||
pattern="\S(.*\S)?"
|
||||
required
|
||||
/>
|
||||
</label>
|
||||
<div class="file-field">
|
||||
<label>
|
||||
Favicon:
|
||||
@@ -109,14 +105,7 @@
|
||||
action="?/updateHeader"
|
||||
method="POST"
|
||||
enctype="multipart/form-data"
|
||||
use:enhance={() => {
|
||||
loadingDelay = window.setTimeout(() => (sending = true), 500);
|
||||
return async ({ update }) => {
|
||||
await update({ reset: false });
|
||||
window.clearTimeout(loadingDelay);
|
||||
sending = false;
|
||||
};
|
||||
}}
|
||||
use:enhance={enhanceForm({ reset: false })}
|
||||
>
|
||||
<label>
|
||||
Logo type:
|
||||
@@ -159,30 +148,13 @@
|
||||
<a href="#home">Home</a>
|
||||
</h2>
|
||||
|
||||
<form
|
||||
action="?/updateHome"
|
||||
method="POST"
|
||||
use:enhance={() => {
|
||||
loadingDelay = window.setTimeout(() => (sending = true), 500);
|
||||
return async ({ update }) => {
|
||||
await update({ reset: false });
|
||||
window.clearTimeout(loadingDelay);
|
||||
sending = false;
|
||||
};
|
||||
}}
|
||||
>
|
||||
<label>
|
||||
Main content:
|
||||
<textarea
|
||||
name="main-content"
|
||||
rows="20"
|
||||
bind:value={previewContent}
|
||||
bind:this={mainContentTextarea}
|
||||
onscroll={updateScrollPercentage}
|
||||
onpaste={handlePaste}
|
||||
required>{data.home.main_content}</textarea
|
||||
>
|
||||
</label>
|
||||
<form action="?/updateHome" method="POST" use:enhance={enhanceForm({ reset: false })}>
|
||||
<MarkdownEditor
|
||||
apiPrefix={data.API_BASE_PREFIX}
|
||||
label="Main content"
|
||||
name="main-content"
|
||||
content={data.home.main_content}
|
||||
/>
|
||||
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
@@ -193,18 +165,7 @@
|
||||
<a href="#footer">Footer</a>
|
||||
</h2>
|
||||
|
||||
<form
|
||||
action="?/updateFooter"
|
||||
method="POST"
|
||||
use:enhance={() => {
|
||||
loadingDelay = window.setTimeout(() => (sending = true), 500);
|
||||
return async ({ update }) => {
|
||||
await update({ reset: false });
|
||||
window.clearTimeout(loadingDelay);
|
||||
sending = false;
|
||||
};
|
||||
}}
|
||||
>
|
||||
<form action="?/updateFooter" method="POST" use:enhance={enhanceForm({ reset: false })}>
|
||||
<label>
|
||||
Additional text:
|
||||
<textarea name="additional-text" rows="5" maxlength="250" required
|
||||
|
||||
@@ -6,16 +6,18 @@
|
||||
import SuccessOrError from "$lib/components/SuccessOrError.svelte";
|
||||
import LoadingSpinner from "$lib/components/LoadingSpinner.svelte";
|
||||
import type { ActionData, PageServerData } from "./$types";
|
||||
import { enhanceForm } from "$lib/utils";
|
||||
import { sending } from "$lib/runes.svelte";
|
||||
import { previewContent } from "$lib/runes.svelte";
|
||||
|
||||
const { data, form }: { data: PageServerData; form: ActionData } = $props();
|
||||
|
||||
let sending = $state(false);
|
||||
let loadingDelay: number;
|
||||
previewContent.value = data.home.main_content;
|
||||
</script>
|
||||
|
||||
<SuccessOrError success={form?.success} message={form?.message} />
|
||||
|
||||
{#if sending}
|
||||
{#if sending.value}
|
||||
<LoadingSpinner />
|
||||
{/if}
|
||||
|
||||
@@ -23,7 +25,6 @@
|
||||
id={data.website.id}
|
||||
contentType={data.website.content_type}
|
||||
title={data.website.title}
|
||||
previewContent={data.home.main_content}
|
||||
>
|
||||
<section id="create-article">
|
||||
<h2>
|
||||
@@ -33,19 +34,7 @@
|
||||
<Modal id="create-article" text="Create article">
|
||||
<h3>Create article</h3>
|
||||
|
||||
<form
|
||||
method="POST"
|
||||
action="?/createArticle"
|
||||
use:enhance={() => {
|
||||
loadingDelay = window.setTimeout(() => (sending = true), 500);
|
||||
return async ({ update }) => {
|
||||
await update();
|
||||
window.clearTimeout(loadingDelay);
|
||||
window.location.hash = "!";
|
||||
sending = false;
|
||||
};
|
||||
}}
|
||||
>
|
||||
<form method="POST" action="?/createArticle" use:enhance={enhanceForm({ closeModal: true })}>
|
||||
<label>
|
||||
Title:
|
||||
<input type="text" name="title" pattern="\S(.*\S)?" maxlength="100" required />
|
||||
@@ -136,15 +125,7 @@
|
||||
<form
|
||||
method="POST"
|
||||
action="?/deleteArticle"
|
||||
use:enhance={() => {
|
||||
loadingDelay = window.setTimeout(() => (sending = true), 500);
|
||||
return async ({ update }) => {
|
||||
await update();
|
||||
window.clearTimeout(loadingDelay);
|
||||
window.location.hash = "!";
|
||||
sending = false;
|
||||
};
|
||||
}}
|
||||
use:enhance={enhanceForm({ closeModal: true })}
|
||||
>
|
||||
<input type="hidden" name="id" value={id} />
|
||||
|
||||
|
||||
@@ -6,34 +6,19 @@
|
||||
import type { ActionData, PageServerData } from "./$types";
|
||||
import Modal from "$lib/components/Modal.svelte";
|
||||
import LoadingSpinner from "$lib/components/LoadingSpinner.svelte";
|
||||
import { handleImagePaste } from "$lib/utils";
|
||||
import { enhanceForm } from "$lib/utils";
|
||||
import { sending } from "$lib/runes.svelte";
|
||||
import { previewContent } from "$lib/runes.svelte";
|
||||
import MarkdownEditor from "$lib/components/MarkdownEditor.svelte";
|
||||
|
||||
const { data, form }: { data: PageServerData; form: ActionData } = $props();
|
||||
|
||||
let previewContent = $state(data.article.main_content);
|
||||
let mainContentTextarea: HTMLTextAreaElement;
|
||||
let textareaScrollTop = $state(0);
|
||||
|
||||
const updateScrollPercentage = () => {
|
||||
const { scrollTop, scrollHeight, clientHeight } = mainContentTextarea;
|
||||
textareaScrollTop = (scrollTop / (scrollHeight - clientHeight)) * 100;
|
||||
};
|
||||
|
||||
const handlePaste = async (event: ClipboardEvent) => {
|
||||
const newContent = await handleImagePaste(event, data.API_BASE_PREFIX);
|
||||
|
||||
if (newContent) {
|
||||
previewContent = newContent;
|
||||
}
|
||||
};
|
||||
|
||||
let sending = $state(false);
|
||||
let loadingDelay: number;
|
||||
previewContent.value = data.article?.main_content ?? "";
|
||||
</script>
|
||||
|
||||
<SuccessOrError success={form?.success} message={form?.message} />
|
||||
|
||||
{#if sending}
|
||||
{#if sending.value}
|
||||
<LoadingSpinner />
|
||||
{/if}
|
||||
|
||||
@@ -41,9 +26,6 @@
|
||||
id={data.website.id}
|
||||
contentType={data.website.content_type}
|
||||
title={data.website.title}
|
||||
previewContent={previewContent ||
|
||||
"Put some markdown content in main content to see a live preview here"}
|
||||
previewScrollTop={textareaScrollTop}
|
||||
>
|
||||
<section id="edit-article">
|
||||
<h2>
|
||||
@@ -54,14 +36,7 @@
|
||||
method="POST"
|
||||
action="?/editArticle"
|
||||
enctype="multipart/form-data"
|
||||
use:enhance={() => {
|
||||
loadingDelay = window.setTimeout(() => (sending = true), 500);
|
||||
return async ({ update }) => {
|
||||
await update({ reset: false });
|
||||
window.clearTimeout(loadingDelay);
|
||||
sending = false;
|
||||
};
|
||||
}}
|
||||
use:enhance={enhanceForm({ reset: false })}
|
||||
>
|
||||
{#if data.website.content_type === "Docs"}
|
||||
<label>
|
||||
@@ -135,18 +110,12 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<label>
|
||||
Main content:
|
||||
<textarea
|
||||
name="main-content"
|
||||
rows="20"
|
||||
bind:value={previewContent}
|
||||
bind:this={mainContentTextarea}
|
||||
onscroll={updateScrollPercentage}
|
||||
onpaste={handlePaste}
|
||||
required>{data.article.main_content}</textarea
|
||||
>
|
||||
</label>
|
||||
<MarkdownEditor
|
||||
apiPrefix={data.API_BASE_PREFIX}
|
||||
label="Main content"
|
||||
name="main-content"
|
||||
content={data.article.main_content ?? ""}
|
||||
/>
|
||||
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
|
||||
@@ -5,16 +5,18 @@
|
||||
import Modal from "$lib/components/Modal.svelte";
|
||||
import LoadingSpinner from "$lib/components/LoadingSpinner.svelte";
|
||||
import type { ActionData, PageServerData } from "./$types";
|
||||
import { enhanceForm } from "$lib/utils";
|
||||
import { sending } from "$lib/runes.svelte";
|
||||
import { previewContent } from "$lib/runes.svelte";
|
||||
|
||||
const { data, form }: { data: PageServerData; form: ActionData } = $props();
|
||||
|
||||
let sending = $state(false);
|
||||
let loadingDelay: number;
|
||||
previewContent.value = data.home.main_content;
|
||||
</script>
|
||||
|
||||
<SuccessOrError success={form?.success} message={form?.message} />
|
||||
|
||||
{#if sending}
|
||||
{#if sending.value}
|
||||
<LoadingSpinner />
|
||||
{/if}
|
||||
|
||||
@@ -22,7 +24,6 @@
|
||||
id={data.website.id}
|
||||
contentType={data.website.content_type}
|
||||
title={data.website.title}
|
||||
previewContent={data.home.main_content}
|
||||
>
|
||||
<section id="create-category">
|
||||
<h2>
|
||||
@@ -32,19 +33,7 @@
|
||||
<Modal id="create-category" text="Create category">
|
||||
<h3>Create category</h3>
|
||||
|
||||
<form
|
||||
method="POST"
|
||||
action="?/createCategory"
|
||||
use:enhance={() => {
|
||||
loadingDelay = window.setTimeout(() => (sending = true), 500);
|
||||
return async ({ update }) => {
|
||||
await update();
|
||||
window.clearTimeout(loadingDelay);
|
||||
window.location.hash = "!";
|
||||
sending = false;
|
||||
};
|
||||
}}
|
||||
>
|
||||
<form method="POST" action="?/createCategory" use:enhance={enhanceForm({ closeModal: true })}>
|
||||
<label>
|
||||
Name:
|
||||
<input type="text" name="category-name" maxlength="50" required />
|
||||
@@ -80,15 +69,7 @@
|
||||
<form
|
||||
method="POST"
|
||||
action="?/updateCategory"
|
||||
use:enhance={() => {
|
||||
loadingDelay = window.setTimeout(() => (sending = true), 500);
|
||||
return async ({ update }) => {
|
||||
await update({ reset: false });
|
||||
window.clearTimeout(loadingDelay);
|
||||
window.location.hash = "!";
|
||||
sending = false;
|
||||
};
|
||||
}}
|
||||
use:enhance={enhanceForm({ reset: false, closeModal: true })}
|
||||
>
|
||||
<input type="hidden" name="category-id" value={id} />
|
||||
|
||||
@@ -119,15 +100,7 @@
|
||||
<form
|
||||
method="POST"
|
||||
action="?/deleteCategory"
|
||||
use:enhance={() => {
|
||||
loadingDelay = window.setTimeout(() => (sending = true), 500);
|
||||
return async ({ update }) => {
|
||||
await update();
|
||||
window.clearTimeout(loadingDelay);
|
||||
window.location.hash = "!";
|
||||
sending = false;
|
||||
};
|
||||
}}
|
||||
use:enhance={enhanceForm({ closeModal: true })}
|
||||
>
|
||||
<input type="hidden" name="category-id" value={id} />
|
||||
|
||||
|
||||
@@ -4,17 +4,18 @@
|
||||
import SuccessOrError from "$lib/components/SuccessOrError.svelte";
|
||||
import Modal from "$lib/components/Modal.svelte";
|
||||
import LoadingSpinner from "$lib/components/LoadingSpinner.svelte";
|
||||
import { enhanceForm } from "$lib/utils";
|
||||
import { previewContent, sending } from "$lib/runes.svelte";
|
||||
import type { ActionData, PageServerData } from "./$types";
|
||||
|
||||
const { data, form }: { data: PageServerData; form: ActionData } = $props();
|
||||
|
||||
let sending = $state(false);
|
||||
let loadingDelay: number;
|
||||
previewContent.value = data.home.main_content;
|
||||
</script>
|
||||
|
||||
<SuccessOrError success={form?.success} message={form?.message} />
|
||||
|
||||
{#if sending}
|
||||
{#if sending.value}
|
||||
<LoadingSpinner />
|
||||
{/if}
|
||||
|
||||
@@ -22,7 +23,6 @@
|
||||
id={data.website.id}
|
||||
contentType={data.website.content_type}
|
||||
title={data.website.title}
|
||||
previewContent={data.home.main_content}
|
||||
>
|
||||
<section id="add-collaborator">
|
||||
<h2>
|
||||
@@ -35,15 +35,7 @@
|
||||
<form
|
||||
method="POST"
|
||||
action="?/addCollaborator"
|
||||
use:enhance={() => {
|
||||
loadingDelay = window.setTimeout(() => (sending = true), 500);
|
||||
return async ({ update }) => {
|
||||
await update();
|
||||
window.clearTimeout(loadingDelay);
|
||||
window.location.hash = "!";
|
||||
sending = false;
|
||||
};
|
||||
}}
|
||||
use:enhance={enhanceForm({ closeModal: true })}
|
||||
>
|
||||
<label>
|
||||
Username:
|
||||
@@ -84,15 +76,7 @@
|
||||
<form
|
||||
method="POST"
|
||||
action="?/updateCollaborator"
|
||||
use:enhance={() => {
|
||||
loadingDelay = window.setTimeout(() => (sending = true), 500);
|
||||
return async ({ update }) => {
|
||||
await update({ reset: false });
|
||||
window.clearTimeout(loadingDelay);
|
||||
window.location.hash = "!";
|
||||
sending = false;
|
||||
};
|
||||
}}
|
||||
use:enhance={enhanceForm({ reset: false, closeModal: true })}
|
||||
>
|
||||
<input type="hidden" name="user-id" value={user_id} />
|
||||
|
||||
@@ -116,15 +100,7 @@
|
||||
<form
|
||||
method="POST"
|
||||
action="?/removeCollaborator"
|
||||
use:enhance={() => {
|
||||
loadingDelay = window.setTimeout(() => (sending = true), 500);
|
||||
return async ({ update }) => {
|
||||
await update();
|
||||
window.clearTimeout(loadingDelay);
|
||||
window.location.hash = "!";
|
||||
sending = false;
|
||||
};
|
||||
}}
|
||||
use:enhance={enhanceForm({ closeModal: true })}
|
||||
>
|
||||
<input type="hidden" name="user-id" value={user_id} />
|
||||
|
||||
|
||||
@@ -23,7 +23,8 @@ export const load: PageServerLoad = async ({ parent, fetch, params }) => {
|
||||
|
||||
return {
|
||||
legalInformation,
|
||||
website
|
||||
website,
|
||||
API_BASE_PREFIX
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -4,26 +4,19 @@
|
||||
import SuccessOrError from "$lib/components/SuccessOrError.svelte";
|
||||
import LoadingSpinner from "$lib/components/LoadingSpinner.svelte";
|
||||
import Modal from "$lib/components/Modal.svelte";
|
||||
import { enhanceForm } from "$lib/utils";
|
||||
import { sending, previewContent } from "$lib/runes.svelte";
|
||||
import type { ActionData, PageServerData } from "./$types";
|
||||
import MarkdownEditor from "$lib/components/MarkdownEditor.svelte";
|
||||
|
||||
const { data, form }: { data: PageServerData; form: ActionData } = $props();
|
||||
|
||||
let previewContent = $state(data.legalInformation?.main_content);
|
||||
let mainContentTextarea: HTMLTextAreaElement;
|
||||
let textareaScrollTop = $state(0);
|
||||
|
||||
const updateScrollPercentage = () => {
|
||||
const { scrollTop, scrollHeight, clientHeight } = mainContentTextarea;
|
||||
textareaScrollTop = (scrollTop / (scrollHeight - clientHeight)) * 100;
|
||||
};
|
||||
|
||||
let sending = $state(false);
|
||||
let loadingDelay: number;
|
||||
previewContent.value = data.legalInformation?.main_content ?? "";
|
||||
</script>
|
||||
|
||||
<SuccessOrError success={form?.success} message={form?.message} />
|
||||
|
||||
{#if sending}
|
||||
{#if sending.value}
|
||||
<LoadingSpinner />
|
||||
{/if}
|
||||
|
||||
@@ -31,9 +24,6 @@
|
||||
id={data.website.id}
|
||||
contentType={data.website.content_type}
|
||||
title={data.website.title}
|
||||
previewContent={previewContent ||
|
||||
"Put some markdown content in main content to see a live preview here"}
|
||||
previewScrollTop={textareaScrollTop}
|
||||
>
|
||||
<section id="legal-information">
|
||||
<h2>
|
||||
@@ -62,29 +52,14 @@
|
||||
<form
|
||||
method="POST"
|
||||
action="?/createUpdateLegalInformation"
|
||||
use:enhance={() => {
|
||||
loadingDelay = window.setTimeout(() => (sending = true), 500);
|
||||
return async ({ update }) => {
|
||||
await update({ reset: false });
|
||||
window.clearTimeout(loadingDelay);
|
||||
sending = false;
|
||||
};
|
||||
}}
|
||||
use:enhance={enhanceForm({ reset: false })}
|
||||
>
|
||||
<label>
|
||||
Main content:
|
||||
<textarea
|
||||
name="main-content"
|
||||
rows="20"
|
||||
placeholder="## Impressum
|
||||
|
||||
## Privacy policy"
|
||||
bind:value={previewContent}
|
||||
bind:this={mainContentTextarea}
|
||||
onscroll={updateScrollPercentage}
|
||||
required>{data.legalInformation?.main_content ?? ""}</textarea
|
||||
>
|
||||
</label>
|
||||
<MarkdownEditor
|
||||
apiPrefix={data.API_BASE_PREFIX}
|
||||
label="Main content"
|
||||
name="main-content"
|
||||
content={data.legalInformation?.main_content ?? ""}
|
||||
/>
|
||||
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
@@ -94,15 +69,7 @@
|
||||
<form
|
||||
action="?/deleteLegalInformation"
|
||||
method="post"
|
||||
use:enhance={() => {
|
||||
loadingDelay = window.setTimeout(() => (sending = true), 500);
|
||||
return async ({ update }) => {
|
||||
await update();
|
||||
window.clearTimeout(loadingDelay);
|
||||
window.location.hash = "!";
|
||||
sending = false;
|
||||
};
|
||||
}}
|
||||
use:enhance={enhanceForm({ closeModal: true })}
|
||||
>
|
||||
<h3>Delete legal information</h3>
|
||||
<p>
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
import diff from "fast-diff";
|
||||
import { page } from "$app/stores";
|
||||
import { tables } from "$lib/db-schema";
|
||||
import { previewContent } from "$lib/runes.svelte";
|
||||
import { sanitize } from "isomorphic-dompurify";
|
||||
|
||||
const { data }: { data: PageServerData } = $props();
|
||||
|
||||
@@ -45,6 +47,8 @@
|
||||
resources = restTables;
|
||||
}
|
||||
|
||||
previewContent.value = data.home.main_content;
|
||||
|
||||
let logsSection: HTMLElement;
|
||||
</script>
|
||||
|
||||
@@ -52,7 +56,6 @@
|
||||
id={data.website.id}
|
||||
contentType={data.website.content_type}
|
||||
title={data.website.title}
|
||||
previewContent={data.home.main_content}
|
||||
>
|
||||
<section id="logs" bind:this={logsSection}>
|
||||
<hgroup>
|
||||
@@ -153,7 +156,9 @@
|
||||
<p>{table_name} — {operation}</p>
|
||||
</hgroup>
|
||||
|
||||
<pre style="white-space: pre-wrap">{@html htmlDiff(oldValue, newValue)}</pre>
|
||||
<pre style="white-space: pre-wrap">{@html sanitize(htmlDiff(oldValue, newValue), {
|
||||
ALLOWED_TAGS: ["ins", "del"]
|
||||
})}</pre>
|
||||
</Modal>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { readFile, mkdir, writeFile, rename } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
import { type WebsiteOverview, slugify } from "$lib/utils";
|
||||
import type { Actions, PageServerLoad } from "./$types";
|
||||
import { API_BASE_PREFIX, apiRequest } from "$lib/server/utils";
|
||||
import { render } from "svelte/server";
|
||||
import BlogIndex from "$lib/templates/blog/BlogIndex.svelte";
|
||||
import BlogArticle from "$lib/templates/blog/BlogArticle.svelte";
|
||||
import DocsIndex from "$lib/templates/docs/DocsIndex.svelte";
|
||||
import DocsArticle from "$lib/templates/docs/DocsArticle.svelte";
|
||||
import { dev } from "$app/environment";
|
||||
import { API_BASE_PREFIX, apiRequest } from "$lib/server/utils";
|
||||
import BlogArticle from "$lib/templates/blog/BlogArticle.svelte";
|
||||
import BlogIndex from "$lib/templates/blog/BlogIndex.svelte";
|
||||
import DocsArticle from "$lib/templates/docs/DocsArticle.svelte";
|
||||
import DocsIndex from "$lib/templates/docs/DocsIndex.svelte";
|
||||
import { type WebsiteOverview, hexToHSL, slugify } from "$lib/utils";
|
||||
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
import { render } from "svelte/server";
|
||||
import type { Actions, PageServerLoad } from "./$types";
|
||||
|
||||
export const load: PageServerLoad = async ({ params, fetch }) => {
|
||||
const websiteOverview: WebsiteOverview = (
|
||||
@@ -169,8 +169,6 @@ const generateStaticFiles = async (websiteData: WebsiteOverview, isPreview = tru
|
||||
</html>`;
|
||||
};
|
||||
|
||||
console.log(websiteData);
|
||||
|
||||
const { head, body } = render(websiteData.content_type === "Blog" ? BlogIndex : DocsIndex, {
|
||||
props: {
|
||||
websiteOverview: websiteData,
|
||||
@@ -235,21 +233,35 @@ const generateStaticFiles = async (websiteData: WebsiteOverview, isPreview = tru
|
||||
encoding: "utf-8"
|
||||
}
|
||||
);
|
||||
|
||||
const {
|
||||
h: hDark,
|
||||
s: sDark,
|
||||
l: lDark
|
||||
} = hexToHSL(websiteData.settings.background_color_dark_theme);
|
||||
const {
|
||||
h: hLight,
|
||||
s: sLight,
|
||||
l: lLight
|
||||
} = hexToHSL(websiteData.settings.background_color_light_theme);
|
||||
|
||||
await writeFile(
|
||||
join(uploadDir, "styles.css"),
|
||||
commonStyles
|
||||
.concat(specificStyles)
|
||||
.replace(/(?<=\/\* BACKGROUND_COLOR_DARK_THEME_H \*\/\s*).*(?=;)/, ` ${hDark}`)
|
||||
.replace(/(?<=\/\* BACKGROUND_COLOR_DARK_THEME_S \*\/\s*).*(?=;)/, ` ${sDark}%`)
|
||||
.replace(/(?<=\/\* BACKGROUND_COLOR_DARK_THEME_L \*\/\s*).*(?=;)/, ` ${lDark}%`)
|
||||
.replace(/(?<=\/\* BACKGROUND_COLOR_LIGHT_THEME_H \*\/\s*).*(?=;)/, ` ${hLight}`)
|
||||
.replace(/(?<=\/\* BACKGROUND_COLOR_LIGHT_THEME_S \*\/\s*).*(?=;)/, ` ${sLight}%`)
|
||||
.replace(/(?<=\/\* BACKGROUND_COLOR_LIGHT_THEME_L \*\/\s*).*(?=;)/, ` ${lLight}%`)
|
||||
.replace(
|
||||
/--color-accent:\s*(.*?);/,
|
||||
`--color-accent: ${websiteData.settings.accent_color_dark_theme};`
|
||||
/(?<=\/\* ACCENT_COLOR_DARK_THEME \*\/\s*).*(?=;)/,
|
||||
` ${websiteData.settings.accent_color_dark_theme}`
|
||||
)
|
||||
.replace(
|
||||
/@media\s*\(prefers-color-scheme:\s*dark\)\s*{[^}]*--color-accent:\s*(.*?);/,
|
||||
(match) =>
|
||||
match.replace(
|
||||
/--color-accent:\s*(.*?);/,
|
||||
`--color-accent: ${websiteData.settings.accent_color_light_theme};`
|
||||
)
|
||||
/(?<=\/\* ACCENT_COLOR_LIGHT_THEME \*\/\s*).*(?=;)/,
|
||||
` ${websiteData.settings.accent_color_light_theme}`
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
@@ -5,16 +5,18 @@
|
||||
import type { ActionData, PageServerData } from "./$types";
|
||||
import LoadingSpinner from "$lib/components/LoadingSpinner.svelte";
|
||||
import Modal from "$lib/components/Modal.svelte";
|
||||
import { enhanceForm } from "$lib/utils";
|
||||
import { sending } from "$lib/runes.svelte";
|
||||
import { previewContent } from "$lib/runes.svelte";
|
||||
|
||||
const { data, form }: { data: PageServerData; form: ActionData } = $props();
|
||||
|
||||
let sending = $state(false);
|
||||
let loadingDelay: number;
|
||||
previewContent.value = data.websitePreviewUrl;
|
||||
</script>
|
||||
|
||||
<SuccessOrError success={form?.success} message={form?.message} />
|
||||
|
||||
{#if sending}
|
||||
{#if sending.value}
|
||||
<LoadingSpinner />
|
||||
{/if}
|
||||
|
||||
@@ -22,7 +24,6 @@
|
||||
id={data.websiteOverview.id}
|
||||
contentType={data.websiteOverview.content_type}
|
||||
title={data.websiteOverview.title}
|
||||
previewContent={data.websitePreviewUrl}
|
||||
fullPreview={true}
|
||||
>
|
||||
<section id="publish-website">
|
||||
@@ -34,18 +35,7 @@
|
||||
is published. If you are happy with the results, click the button below and your website will
|
||||
be published on the Internet.
|
||||
</p>
|
||||
<form
|
||||
method="POST"
|
||||
action="?/publishWebsite"
|
||||
use:enhance={() => {
|
||||
loadingDelay = window.setTimeout(() => (sending = true), 500);
|
||||
return async ({ update }) => {
|
||||
await update();
|
||||
window.clearTimeout(loadingDelay);
|
||||
sending = false;
|
||||
};
|
||||
}}
|
||||
>
|
||||
<form method="POST" action="?/publishWebsite" use:enhance={enhanceForm()}>
|
||||
<button type="submit">Publish</button>
|
||||
</form>
|
||||
</section>
|
||||
@@ -69,14 +59,7 @@
|
||||
<form
|
||||
method="POST"
|
||||
action="?/createUpdateCustomDomainPrefix"
|
||||
use:enhance={() => {
|
||||
loadingDelay = window.setTimeout(() => (sending = true), 500);
|
||||
return async ({ update }) => {
|
||||
await update();
|
||||
window.clearTimeout(loadingDelay);
|
||||
sending = false;
|
||||
};
|
||||
}}
|
||||
use:enhance={enhanceForm({ reset: false })}
|
||||
>
|
||||
<label>
|
||||
Prefix:
|
||||
@@ -98,15 +81,7 @@
|
||||
<form
|
||||
action="?/deleteCustomDomainPrefix"
|
||||
method="post"
|
||||
use:enhance={() => {
|
||||
loadingDelay = window.setTimeout(() => (sending = true), 500);
|
||||
return async ({ update }) => {
|
||||
await update();
|
||||
window.clearTimeout(loadingDelay);
|
||||
window.location.hash = "!";
|
||||
sending = false;
|
||||
};
|
||||
}}
|
||||
use:enhance={enhanceForm({ closeModal: true })}
|
||||
>
|
||||
<h3>Delete domain prefix</h3>
|
||||
<p>
|
||||
|
||||
Reference in New Issue
Block a user