Share styles and update props

This commit is contained in:
thiloho
2024-08-20 19:17:05 +02:00
parent bf791f9bfc
commit 0cbf0bd866
29 changed files with 343 additions and 369 deletions

View File

@@ -56,8 +56,6 @@
program = "${pkgs.writeShellScriptBin "api-setup" '' program = "${pkgs.writeShellScriptBin "api-setup" ''
${pkgs.postgresql_16}/bin/psql postgres://postgres@localhost:15432/archtika -c "ALTER DATABASE archtika SET \"app.jwt_secret\" TO 'a42kVyAhTImYxZeebZkApoAZLmf0VtDA'" ${pkgs.postgresql_16}/bin/psql postgres://postgres@localhost:15432/archtika -c "ALTER DATABASE archtika SET \"app.jwt_secret\" TO 'a42kVyAhTImYxZeebZkApoAZLmf0VtDA'"
echo "OUT PATH: ${self.outPath}"
${pkgs.dbmate}/bin/dbmate --url postgres://postgres@localhost:15432/archtika?sslmode=disable --migrations-dir ${self.outPath}/rest-api/db/migrations up ${pkgs.dbmate}/bin/dbmate --url postgres://postgres@localhost:15432/archtika?sslmode=disable --migrations-dir ${self.outPath}/rest-api/db/migrations up
PGRST_DB_SCHEMAS="api" PGRST_DB_ANON_ROLE="anon" PGRST_OPENAPI_MODE="ignore-privileges" PGRST_DB_URI="postgres://authenticator@localhost:15432/archtika" PGRST_JWT_SECRET="a42kVyAhTImYxZeebZkApoAZLmf0VtDA" ${pkgs.postgrest}/bin/postgrest PGRST_DB_SCHEMAS="api" PGRST_DB_ANON_ROLE="anon" PGRST_OPENAPI_MODE="ignore-privileges" PGRST_DB_URI="postgres://authenticator@localhost:15432/archtika" PGRST_JWT_SECRET="a42kVyAhTImYxZeebZkApoAZLmf0VtDA" ${pkgs.postgrest}/bin/postgrest

View File

@@ -1,93 +1,3 @@
:root {
--bg-primary: white;
--bg-secondary: hsl(0 0% 95%);
--bg-tertiary: hsl(0 0% 90%);
--color-text: black;
--color-text-invert: white;
--color-accent: hsl(210, 100%, 30%);
--color-success: hsl(105, 100%, 30%);
--color-error: hsl(0, 100%, 30%);
--border-primary: 0.0625rem solid var(--bg-tertiary);
--border-radius: 0.125rem;
/* Step -1: 14.9953px → 14.2222px */
--font-size--1: clamp(0.8889rem, 0.9592rem + -0.1098cqi, 0.9372rem);
/* Step 0: 16px → 16px */
--font-size-0: clamp(1rem, 1rem + 0cqi, 1rem);
/* Step 1: 17.072px → 18px */
--font-size-1: clamp(1.067rem, 1.0406rem + 0.1318cqi, 1.125rem);
/* Step 2: 18.2158px → 20.25px */
--font-size-2: clamp(1.1385rem, 1.0807rem + 0.2889cqi, 1.2656rem);
/* Step 3: 19.4363px → 22.7813px */
--font-size-3: clamp(1.2148rem, 1.1197rem + 0.4751cqi, 1.4238rem);
/* Step 4: 20.7385px → 25.6289px */
--font-size-4: clamp(1.2962rem, 1.1572rem + 0.6947cqi, 1.6018rem);
/* Step 5: 22.128px → 28.8325px */
--font-size-5: clamp(1.383rem, 1.1925rem + 0.9523cqi, 1.802rem);
/* Space 3xs: 4px → 5px */
--space-3xs: clamp(0.25rem, 0.2336rem + 0.0822cqi, 0.3125rem);
/* Space 2xs: 8px → 10px */
--space-2xs: clamp(0.5rem, 0.4671rem + 0.1645cqi, 0.625rem);
/* Space xs: 12px → 15px */
--space-xs: clamp(0.75rem, 0.7007rem + 0.2467cqi, 0.9375rem);
/* Space s: 16px → 20px */
--space-s: clamp(1rem, 0.9342rem + 0.3289cqi, 1.25rem);
/* Space m: 24px → 30px */
--space-m: clamp(1.5rem, 1.4013rem + 0.4934cqi, 1.875rem);
/* Space l: 32px → 40px */
--space-l: clamp(2rem, 1.8684rem + 0.6579cqi, 2.5rem);
/* Space xl: 48px → 60px */
--space-xl: clamp(3rem, 2.8026rem + 0.9868cqi, 3.75rem);
/* Space 2xl: 64px → 80px */
--space-2xl: clamp(4rem, 3.7368rem + 1.3158cqi, 5rem);
/* Space 3xl: 96px → 120px */
--space-3xl: clamp(6rem, 5.6053rem + 1.9737cqi, 7.5rem);
color-scheme: light;
}
@media (prefers-color-scheme: dark) {
:root {
--bg-primary: hsl(0 0% 15%);
--bg-secondary: hsl(0 0% 20%);
--bg-tertiary: hsl(0 0% 25%);
--color-text: white;
--color-text-invert: black;
--color-accent: hsl(210, 100%, 80%);
--color-success: hsl(105, 100%, 80%);
--color-error: hsl(0, 100%, 80%);
color-scheme: dark;
}
}
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
line-height: 1.5;
font-family: system-ui, sans-serif;
background-color: var(--bg-primary);
display: flex;
flex-direction: column;
min-block-size: 100vh;
}
section {
display: flex;
flex-direction: column;
gap: var(--space-s);
}
section + section { section + section {
margin-block-start: var(--space-l); margin-block-start: var(--space-l);
} }
@@ -135,10 +45,6 @@ input[type="color"] {
padding: 0; padding: 0;
} }
a {
color: var(--color-accent);
}
a[role="button"] { a[role="button"] {
display: inline-block; display: inline-block;
max-inline-size: fit-content; max-inline-size: fit-content;
@@ -149,10 +55,6 @@ summary {
max-inline-size: fit-content; max-inline-size: fit-content;
} }
details[open] summary {
margin-block-end: var(--space-s);
}
button, button,
a[role="button"], a[role="button"],
label[for="toggle-mobile-preview"], label[for="toggle-mobile-preview"],
@@ -170,48 +72,11 @@ summary {
outline-offset: 0.25rem; outline-offset: 0.25rem;
} }
img,
picture,
svg,
video {
max-inline-size: 100%;
block-size: auto;
}
ul, ul,
ol { ol {
list-style: none; list-style: none;
} }
p,
h1,
h2,
h3,
h4,
h5,
h6 {
overflow-wrap: break-word;
}
h6 {
font-size: var(--font-size-0);
}
h5 {
font-size: var(--font-size-1);
}
h4 {
font-size: var(--font-size-2);
}
h3 {
font-size: var(--font-size-3);
}
h2 {
font-size: var(--font-size-4);
}
h1 {
font-size: var(--font-size-5);
}
form { form {
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View File

@@ -4,22 +4,6 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.svg" /> <link rel="icon" href="%sveltekit.assets%/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<link
rel="stylesheet"
media="(prefers-color-scheme: light)"
href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.10.0/styles/github.min.css"
integrity="sha512-0aPQyyeZrWj9sCA46UlmWgKOP0mUipLQ6OZXu8l4IcAmD2u31EPEy9VcIMvl7SoAaKe8bLXZhYoMaE/in+gcgA=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
<link
rel="stylesheet"
media="(prefers-color-scheme: dark)"
href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.10.0/styles/github-dark.min.css"
integrity="sha512-rO+olRTkcf304DQBxSWxln8JXCzTHlKnIdnMUwYvQa9/Jd4cQaNkItIUj6Z4nvW1dqK0SKXLbn9h4KwZTNtAyw=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
%sveltekit.head% %sveltekit.head%
</head> </head>
<body data-sveltekit-preload-data="hover"> <body data-sveltekit-preload-data="hover">

View File

@@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
const { date } = $props<{ date: string }>(); const { date }: { date: string } = $props();
const options: Intl.DateTimeFormatOptions = { const options: Intl.DateTimeFormatOptions = {
year: "numeric", year: "numeric",

View File

@@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import type { Snippet } from "svelte"; import type { Snippet } from "svelte";
const { children, id, text } = $props<{ children: Snippet; id: string; text: string }>(); const { children, id, text }: { children: Snippet; id: string; text: string } = $props();
</script> </script>
<a href={`#${id}`} role="button">{text}</a> <a href={`#${id}`} role="button">{text}</a>

View File

@@ -1,8 +1,6 @@
<script lang="ts"> <script lang="ts">
const { success, message } = $props<{ const { success, message }: { success: boolean | undefined; message: string | undefined } =
success: boolean | undefined; $props();
message: string;
}>();
</script> </script>
{#if success} {#if success}

View File

@@ -9,14 +9,14 @@
fullPreview = false, fullPreview = false,
previewContent, previewContent,
previewScrollTop = 0 previewScrollTop = 0
} = $props<{ }: {
id: string; id: string;
title: string; title: string;
children: Snippet; children: Snippet;
fullPreview?: boolean; fullPreview?: boolean;
previewContent: string; previewContent: string;
previewScrollTop?: number; previewScrollTop?: number;
}>(); } = $props();
let previewElement: HTMLDivElement; let previewElement: HTMLDivElement;

View File

@@ -1,54 +1,30 @@
<script lang="ts"> <script lang="ts">
const { title, logoType, logo, mainContent, coverImage, publicationDate, footerAdditionalText } = import BlogHead from "./common/BlogHead.svelte";
$props<{ import BlogNav from "./common/BlogNav.svelte";
title: string; import BlogFooter from "./common/BlogFooter.svelte";
logoType: "text" | "image";
logo: string; const {
mainContent: string; title,
coverImage: string; logoType,
publicationDate: string; logo,
footerAdditionalText: string; mainContent,
}>(); coverImage,
publicationDate,
footerAdditionalText
}: {
title: string;
logoType: "text" | "image";
logo: string;
mainContent: string;
coverImage: string;
publicationDate: string;
footerAdditionalText: string;
} = $props();
</script> </script>
<svelte:head> <BlogHead {title} nestingLevel={1} />
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
rel="stylesheet"
media="(prefers-color-scheme: light)"
href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.10.0/styles/github.min.css"
integrity="sha512-0aPQyyeZrWj9sCA46UlmWgKOP0mUipLQ6OZXu8l4IcAmD2u31EPEy9VcIMvl7SoAaKe8bLXZhYoMaE/in+gcgA=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
<link
rel="stylesheet"
media="(prefers-color-scheme: dark)"
href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.10.0/styles/github-dark.min.css"
integrity="sha512-rO+olRTkcf304DQBxSWxln8JXCzTHlKnIdnMUwYvQa9/Jd4cQaNkItIUj6Z4nvW1dqK0SKXLbn9h4KwZTNtAyw=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
<title>{title}</title>
<link rel="stylesheet" href="../styles.css" />
</head>
</svelte:head>
<nav> <BlogNav {logoType} {logo} />
<div class="container">
<a href="../">
{#if logoType === "text"}
<p>
<strong>{logo}</strong>
</p>
{:else}
<img src={logo} alt="" />
{/if}
</a>
</div>
</nav>
<header> <header>
<div class="container"> <div class="container">
@@ -62,14 +38,12 @@
</div> </div>
</header> </header>
<main> {#if mainContent}
<div class="container"> <main>
{@html mainContent} <div class="container">
</div> {@html mainContent}
</main> </div>
</main>
{/if}
<footer> <BlogFooter text={footerAdditionalText} />
<div class="container">
{footerAdditionalText}
</div>
</footer>

View File

@@ -1,52 +1,28 @@
<script lang="ts"> <script lang="ts">
const { title, logoType, logo, mainContent, articles, footerAdditionalText } = $props<{ import BlogHead from "./common/BlogHead.svelte";
import BlogNav from "./common/BlogNav.svelte";
import BlogFooter from "./common/BlogFooter.svelte";
const {
title,
logoType,
logo,
mainContent,
articles,
footerAdditionalText
}: {
title: string; title: string;
logoType: "text" | "image"; logoType: "text" | "image";
logo: string; logo: string;
mainContent: string; mainContent: string;
articles: any[]; articles: { title: string; publication_date: string; meta_description: string }[];
footerAdditionalText: string; footerAdditionalText: string;
}>(); } = $props();
</script> </script>
<svelte:head> <BlogHead {title} />
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
rel="stylesheet"
media="(prefers-color-scheme: light)"
href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.10.0/styles/github.min.css"
integrity="sha512-0aPQyyeZrWj9sCA46UlmWgKOP0mUipLQ6OZXu8l4IcAmD2u31EPEy9VcIMvl7SoAaKe8bLXZhYoMaE/in+gcgA=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
<link
rel="stylesheet"
media="(prefers-color-scheme: dark)"
href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.10.0/styles/github-dark.min.css"
integrity="sha512-rO+olRTkcf304DQBxSWxln8JXCzTHlKnIdnMUwYvQa9/Jd4cQaNkItIUj6Z4nvW1dqK0SKXLbn9h4KwZTNtAyw=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
<title>{title}</title>
<link rel="stylesheet" href="./styles.css" />
</head>
</svelte:head>
<nav> <BlogNav {logoType} {logo} />
<div class="container">
<a href="../">
{#if logoType === "text"}
<p>
<strong>{logo}</strong>
</p>
{:else}
<img src={logo} alt="" />
{/if}
</a>
</div>
</nav>
<header> <header>
<div class="container"> <div class="container">
@@ -66,9 +42,11 @@
{@const articleFileName = article.title.toLowerCase().split(" ").join("-")} {@const articleFileName = article.title.toLowerCase().split(" ").join("-")}
<li> <li>
<p>{article.publication_date}</p> <p>{article.publication_date}</p>
<h3> <p>
<a href="./articles/{articleFileName}.html">{article.title}</a> <strong>
</h3> <a href="./articles/{articleFileName}.html">{article.title}</a>
</strong>
</p>
{#if article.meta_description} {#if article.meta_description}
<p>{article.meta_description}</p> <p>{article.meta_description}</p>
{/if} {/if}
@@ -80,8 +58,4 @@
</div> </div>
</main> </main>
<footer> <BlogFooter text={footerAdditionalText} />
<div class="container">
{footerAdditionalText}
</div>
</footer>

View File

@@ -0,0 +1,11 @@
<script lang="ts">
const { text }: { text: string } = $props();
</script>
<footer>
<div class="container">
<small>
{text}
</small>
</div>
</footer>

View File

@@ -0,0 +1,12 @@
<script lang="ts">
const { title, nestingLevel = 0 }: { title: string; nestingLevel?: number } = $props();
</script>
<svelte:head>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{title}</title>
<link rel="stylesheet" href={`${"../".repeat(nestingLevel)}styles.css`} />
</head>
</svelte:head>

View File

@@ -0,0 +1,17 @@
<script lang="ts">
const { logoType, logo }: { logoType: "text" | "image"; logo: string } = $props();
</script>
<nav>
<div class="container">
<a href="../">
{#if logoType === "text"}
<p>
<strong>{logo}</strong>
</p>
{:else}
<img src={logo} alt="" />
{/if}
</a>
</div>
</nav>

View File

@@ -1,14 +1,21 @@
<script lang="ts"> <script lang="ts">
const { title, logoType, logo, mainContent, coverImage, publicationDate, footerAdditionalText } = const {
$props<{ title,
title: string; logoType,
logoType: "text" | "image"; logo,
logo: string; mainContent,
mainContent: string; coverImage,
coverImage: string; publicationDate,
publicationDate: string; footerAdditionalText
footerAdditionalText: string; }: {
}>(); title: string;
logoType: "text" | "image";
logo: string;
mainContent: string;
coverImage: string;
publicationDate: string;
footerAdditionalText: string;
} = $props();
</script> </script>
<svelte:head> <svelte:head>

View File

@@ -1,12 +1,19 @@
<script lang="ts"> <script lang="ts">
const { title, logoType, logo, mainContent, articles, footerAdditionalText } = $props<{ const {
title,
logoType,
logo,
mainContent,
articles,
footerAdditionalText
}: {
title: string; title: string;
logoType: "text" | "image"; logoType: "text" | "image";
logo: string; logo: string;
mainContent: string; mainContent: string;
articles: any[]; articles: { title: string; publication_date: string; meta_description: string }[];
footerAdditionalText: string; footerAdditionalText: string;
}>(); } = $props();
</script> </script>
<svelte:head> <svelte:head>

View File

@@ -1,7 +1,6 @@
import markdownit from "markdown-it"; import markdownit from "markdown-it";
import hljs from "highlight.js"; import hljs from "highlight.js";
import type { StateCore } from "markdown-it/index.js"; import type { StateCore } from "markdown-it/index.js";
import { dev } from "$app/environment";
export const sortOptions = [ export const sortOptions = [
{ value: "creation-time", text: "Creation time" }, { value: "creation-time", text: "Creation time" },
@@ -117,7 +116,7 @@ export const handleImagePaste = async (event: ClipboardEvent, API_BASE_PREFIX: s
const clipboardItems = Array.from(event.clipboardData?.items || []); const clipboardItems = Array.from(event.clipboardData?.items || []);
const file = clipboardItems.find((item) => item.type.startsWith("image/")); const file = clipboardItems.find((item) => item.type.startsWith("image/"));
if (!file) return; if (!file) return null;
event.preventDefault(); event.preventDefault();

View File

@@ -3,7 +3,7 @@
import SuccessOrError from "$lib/components/SuccessOrError.svelte"; import SuccessOrError from "$lib/components/SuccessOrError.svelte";
import type { ActionData } from "./$types"; import type { ActionData } from "./$types";
const { form } = $props<{ form: ActionData }>(); const { form }: { form: ActionData } = $props();
</script> </script>
<SuccessOrError success={form?.success} message={form?.message} /> <SuccessOrError success={form?.success} message={form?.message} />

View File

@@ -3,7 +3,7 @@
import SuccessOrError from "$lib/components/SuccessOrError.svelte"; import SuccessOrError from "$lib/components/SuccessOrError.svelte";
import type { ActionData } from "./$types"; import type { ActionData } from "./$types";
const { form } = $props<{ form: ActionData }>(); const { form }: { form: ActionData } = $props();
</script> </script>
<SuccessOrError success={form?.success} message={form?.message} /> <SuccessOrError success={form?.success} message={form?.message} />

View File

@@ -7,7 +7,7 @@
import SuccessOrError from "$lib/components/SuccessOrError.svelte"; import SuccessOrError from "$lib/components/SuccessOrError.svelte";
import type { ActionData, PageServerData } from "./$types"; import type { ActionData, PageServerData } from "./$types";
const { form, data } = $props<{ form: ActionData; data: PageServerData }>(); const { form, data }: { form: ActionData; data: PageServerData } = $props();
</script> </script>
<SuccessOrError success={form?.success} message={form?.message} /> <SuccessOrError success={form?.success} message={form?.message} />

View File

@@ -4,7 +4,7 @@
import SuccessOrError from "$lib/components/SuccessOrError.svelte"; import SuccessOrError from "$lib/components/SuccessOrError.svelte";
import type { ActionData, PageServerData } from "./$types"; import type { ActionData, PageServerData } from "./$types";
const { data, form } = $props<{ data: PageServerData; form: ActionData }>(); const { data, form }: { data: PageServerData; form: ActionData } = $props();
</script> </script>
<SuccessOrError success={form?.success} message={form?.message} /> <SuccessOrError success={form?.success} message={form?.message} />

View File

@@ -3,10 +3,10 @@
import WebsiteEditor from "$lib/components/WebsiteEditor.svelte"; import WebsiteEditor from "$lib/components/WebsiteEditor.svelte";
import { ALLOWED_MIME_TYPES, handleImagePaste } from "$lib/utils"; import { ALLOWED_MIME_TYPES, handleImagePaste } from "$lib/utils";
import SuccessOrError from "$lib/components/SuccessOrError.svelte"; import SuccessOrError from "$lib/components/SuccessOrError.svelte";
import type { ActionData, PageServerData } from "./$types"; import type { ActionData, LayoutServerData, PageServerData } from "./$types";
import Modal from "$lib/components/Modal.svelte"; import Modal from "$lib/components/Modal.svelte";
const { data, form } = $props<{ data: PageServerData; form: ActionData }>(); const { data, form }: { data: PageServerData & LayoutServerData; form: ActionData } = $props();
let previewContent = $state(data.home.main_content); let previewContent = $state(data.home.main_content);
let mainContentTextarea: HTMLTextAreaElement; let mainContentTextarea: HTMLTextAreaElement;
@@ -19,7 +19,10 @@
const handlePaste = async (event: ClipboardEvent) => { const handlePaste = async (event: ClipboardEvent) => {
const newContent = await handleImagePaste(event, data.API_BASE_PREFIX); const newContent = await handleImagePaste(event, data.API_BASE_PREFIX);
previewContent = newContent;
if (newContent) {
previewContent = newContent;
}
}; };
</script> </script>

View File

@@ -7,7 +7,7 @@
import SuccessOrError from "$lib/components/SuccessOrError.svelte"; import SuccessOrError from "$lib/components/SuccessOrError.svelte";
import type { ActionData, PageServerData } from "./$types"; import type { ActionData, PageServerData } from "./$types";
const { data, form } = $props<{ data: PageServerData; form: ActionData }>(); const { data, form }: { data: PageServerData; form: ActionData } = $props();
</script> </script>
<SuccessOrError success={form?.success} message={form?.message} /> <SuccessOrError success={form?.success} message={form?.message} />

View File

@@ -7,7 +7,7 @@
import Modal from "$lib/components/Modal.svelte"; import Modal from "$lib/components/Modal.svelte";
import { handleImagePaste } from "$lib/utils"; import { handleImagePaste } from "$lib/utils";
const { data, form } = $props<{ data: PageServerData; form: ActionData }>(); const { data, form }: { data: PageServerData; form: ActionData } = $props();
let previewContent = $state(data.article.main_content); let previewContent = $state(data.article.main_content);
let mainContentTextarea: HTMLTextAreaElement; let mainContentTextarea: HTMLTextAreaElement;
@@ -20,7 +20,9 @@
const handlePaste = async (event: ClipboardEvent) => { const handlePaste = async (event: ClipboardEvent) => {
const newContent = await handleImagePaste(event, data.API_BASE_PREFIX); const newContent = await handleImagePaste(event, data.API_BASE_PREFIX);
previewContent = newContent; if (newContent) {
previewContent = newContent;
}
}; };
</script> </script>

View File

@@ -5,7 +5,7 @@
import Modal from "$lib/components/Modal.svelte"; import Modal from "$lib/components/Modal.svelte";
import type { ActionData, PageServerData } from "./$types"; import type { ActionData, PageServerData } from "./$types";
const { data, form } = $props<{ data: PageServerData; form: ActionData }>(); const { data, form }: { data: PageServerData; form: ActionData } = $props();
</script> </script>
<SuccessOrError success={form?.success} message={form?.message} /> <SuccessOrError success={form?.success} message={form?.message} />

View File

@@ -10,7 +10,7 @@ import DocsIndex from "$lib/templates/docs/DocsIndex.svelte";
import DocsEntry from "$lib/templates/docs/DocsEntry.svelte"; import DocsEntry from "$lib/templates/docs/DocsEntry.svelte";
import { dev } from "$app/environment"; import { dev } from "$app/environment";
export const load: PageServerLoad = async ({ params, fetch, cookies }) => { export const load: PageServerLoad = async ({ params, fetch, cookies, parent }) => {
const websiteOverviewData = await fetch( const websiteOverviewData = await fetch(
`${API_BASE_PREFIX}/website_overview?id=eq.${params.websiteId}`, `${API_BASE_PREFIX}/website_overview?id=eq.${params.websiteId}`,
{ {
@@ -24,6 +24,7 @@ export const load: PageServerLoad = async ({ params, fetch, cookies }) => {
); );
const websiteOverview = await websiteOverviewData.json(); const websiteOverview = await websiteOverviewData.json();
const { website } = await parent();
generateStaticFiles(websiteOverview); generateStaticFiles(websiteOverview);
@@ -31,7 +32,8 @@ export const load: PageServerLoad = async ({ params, fetch, cookies }) => {
return { return {
websiteOverview, websiteOverview,
websitePreviewUrl websitePreviewUrl,
website
}; };
}; };
@@ -152,8 +154,11 @@ const generateStaticFiles = async (websiteData: any, isPreview: boolean = true)
); );
} }
const styles = await readFile(`${process.cwd()}/template-styles/blog-styles.css`, { const commonStyles = await readFile(`${process.cwd()}/template-styles/common-styles.css`, {
encoding: "utf-8" encoding: "utf-8"
}); });
await writeFile(join(uploadDir, "styles.css"), styles); const specificStyles = await readFile(`${process.cwd()}/template-styles/blog-styles.css`, {
encoding: "utf-8"
});
await writeFile(join(uploadDir, "styles.css"), commonStyles.concat(specificStyles));
}; };

View File

@@ -4,7 +4,7 @@
import SuccessOrError from "$lib/components/SuccessOrError.svelte"; import SuccessOrError from "$lib/components/SuccessOrError.svelte";
import type { ActionData, PageServerData } from "./$types"; import type { ActionData, PageServerData } from "./$types";
const { data, form } = $props<{ data: PageServerData; form: ActionData }>(); const { data, form }: { data: PageServerData; form: ActionData } = $props();
</script> </script>
<SuccessOrError success={form?.success} message={form?.message} /> <SuccessOrError success={form?.success} message={form?.message} />

View File

@@ -1,10 +1,11 @@
<script lang="ts"> <script lang="ts">
import "../app.css"; import "../app.css";
import "../../template-styles/common-styles.css";
import { page } from "$app/stores"; import { page } from "$app/stores";
import type { LayoutServerData } from "./$types"; import type { LayoutServerData } from "./$types";
import type { Snippet } from "svelte"; import type { Snippet } from "svelte";
const { data, children } = $props<{ data: LayoutServerData; children: Snippet }>(); const { data, children }: { data: LayoutServerData; children: Snippet } = $props();
const isProjectRoute = $derived($page.url.pathname.startsWith("/website") && !$page.error); const isProjectRoute = $derived($page.url.pathname.startsWith("/website") && !$page.error);
const routeName = $derived( const routeName = $derived(

View File

@@ -1,43 +1,3 @@
@font-face {
font-family: "JetBrains Mono";
font-style: normal;
font-display: swap;
font-weight: 400;
src:
url(https://cdn.jsdelivr.net/fontsource/fonts/jetbrains-mono@latest/latin-400-normal.woff2)
format("woff2"),
url(https://cdn.jsdelivr.net/fontsource/fonts/jetbrains-mono@latest/latin-400-normal.woff)
format("woff");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304,
U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF,
U+FFFD;
}
:root {
color-scheme: light dark;
}
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
line-height: 1.5;
font-family: system-ui, sans-serif;
}
img,
picture,
svg,
video {
max-inline-size: 100%;
block-size: auto;
}
ul, ul,
ol { ol {
list-style: inside; list-style: inside;
@@ -45,60 +5,37 @@ ol {
.container { .container {
margin-inline: auto; margin-inline: auto;
inline-size: min(100% - 2rem, 75ch); inline-size: min(100% - var(--space-m), 75ch);
} }
header > .container { header > .container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 1rem; gap: var(--space-s);
} }
nav, nav,
header, header,
main, main,
footer { footer {
padding-block: 1rem; padding-block: var(--space-s);
} }
section:has(> h2) + section:has(> h2) { section:has(> h2) + section:has(> h2) {
margin-block-start: 2rem; margin-block-start: var(--space-l);
}
section {
display: flex;
flex-direction: column;
gap: 1rem;
} }
.articles ul { .articles ul {
display: grid; display: grid;
list-style: none; list-style: none;
gap: 1rem; gap: var(--space-s);
grid-template-columns: repeat(auto-fit, minmax(min(100%, 30ch), 1fr)); grid-template-columns: repeat(auto-fit, minmax(min(100%, 30ch), 1fr));
} }
.articles li { .articles li {
border: 1px solid hsl(0 0% 50%); border: 1px solid hsl(0 0% 50%);
padding: 1rem; padding: var(--space-s);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 0.5rem; gap: var(--space-xs);
}
pre {
border: 1px solid hsl(0 0% 50%);
padding: 1rem;
overflow-x: auto;
}
code {
font-family: "JetBrains Mono", monospace;
font-size: 0.875rem;
}
:not(pre) > code {
background-color: hsl(0 0% 25%);
padding-inline: 0.25rem;
padding-block: 0.125rem;
} }

View File

@@ -0,0 +1,175 @@
@import url("https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.10.0/styles/github.min.css")
screen and (prefers-color-scheme: light);
@import url("https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.10.0/styles/github-dark.min.css")
screen and (prefers-color-scheme: dark);
@font-face {
font-family: "JetBrains Mono";
font-style: normal;
font-display: swap;
font-weight: 400;
src:
url(https://cdn.jsdelivr.net/fontsource/fonts/jetbrains-mono@latest/latin-400-normal.woff2)
format("woff2"),
url(https://cdn.jsdelivr.net/fontsource/fonts/jetbrains-mono@latest/latin-400-normal.woff)
format("woff");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304,
U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF,
U+FFFD;
}
:root {
--bg-primary: white;
--bg-secondary: hsl(0 0% 95%);
--bg-tertiary: hsl(0 0% 90%);
--color-text: black;
--color-text-invert: white;
--color-accent: hsl(210, 100%, 30%);
--color-success: hsl(105, 100%, 30%);
--color-error: hsl(0, 100%, 30%);
--border-primary: 0.0625rem solid var(--bg-tertiary);
--border-radius: 0.125rem;
/* Step -1: 14.9953px → 14.2222px */
--font-size--1: clamp(0.8889rem, 0.9592rem + -0.1098cqi, 0.9372rem);
/* Step 0: 16px → 16px */
--font-size-0: clamp(1rem, 1rem + 0cqi, 1rem);
/* Step 1: 17.072px → 18px */
--font-size-1: clamp(1.067rem, 1.0406rem + 0.1318cqi, 1.125rem);
/* Step 2: 18.2158px → 20.25px */
--font-size-2: clamp(1.1385rem, 1.0807rem + 0.2889cqi, 1.2656rem);
/* Step 3: 19.4363px → 22.7813px */
--font-size-3: clamp(1.2148rem, 1.1197rem + 0.4751cqi, 1.4238rem);
/* Step 4: 20.7385px → 25.6289px */
--font-size-4: clamp(1.2962rem, 1.1572rem + 0.6947cqi, 1.6018rem);
/* Step 5: 22.128px → 28.8325px */
--font-size-5: clamp(1.383rem, 1.1925rem + 0.9523cqi, 1.802rem);
/* Space 3xs: 4px → 5px */
--space-3xs: clamp(0.25rem, 0.2336rem + 0.0822cqi, 0.3125rem);
/* Space 2xs: 8px → 10px */
--space-2xs: clamp(0.5rem, 0.4671rem + 0.1645cqi, 0.625rem);
/* Space xs: 12px → 15px */
--space-xs: clamp(0.75rem, 0.7007rem + 0.2467cqi, 0.9375rem);
/* Space s: 16px → 20px */
--space-s: clamp(1rem, 0.9342rem + 0.3289cqi, 1.25rem);
/* Space m: 24px → 30px */
--space-m: clamp(1.5rem, 1.4013rem + 0.4934cqi, 1.875rem);
/* Space l: 32px → 40px */
--space-l: clamp(2rem, 1.8684rem + 0.6579cqi, 2.5rem);
/* Space xl: 48px → 60px */
--space-xl: clamp(3rem, 2.8026rem + 0.9868cqi, 3.75rem);
/* Space 2xl: 64px → 80px */
--space-2xl: clamp(4rem, 3.7368rem + 1.3158cqi, 5rem);
/* Space 3xl: 96px → 120px */
--space-3xl: clamp(6rem, 5.6053rem + 1.9737cqi, 7.5rem);
color-scheme: light;
}
@media (prefers-color-scheme: dark) {
:root {
--bg-primary: hsl(0 0% 15%);
--bg-secondary: hsl(0 0% 20%);
--bg-tertiary: hsl(0 0% 25%);
--color-text: white;
--color-text-invert: black;
--color-accent: hsl(210, 100%, 80%);
--color-success: hsl(105, 100%, 80%);
--color-error: hsl(0, 100%, 80%);
color-scheme: dark;
}
}
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
line-height: 1.5;
font-family: system-ui, sans-serif;
background-color: var(--bg-primary);
display: flex;
flex-direction: column;
min-block-size: 100vh;
}
section {
display: flex;
flex-direction: column;
gap: var(--space-s);
}
a {
color: var(--color-accent);
}
details[open] summary {
margin-block-end: var(--space-s);
}
img,
picture,
svg,
video {
max-inline-size: 100%;
block-size: auto;
}
p,
h1,
h2,
h3,
h4,
h5,
h6 {
overflow-wrap: break-word;
}
h6 {
font-size: var(--font-size-0);
}
h5 {
font-size: var(--font-size-1);
}
h4 {
font-size: var(--font-size-2);
}
h3 {
font-size: var(--font-size-3);
}
h2 {
font-size: var(--font-size-4);
}
h1 {
font-size: var(--font-size-5);
}
small {
font-size: var(--font-size--1);
}
pre {
border: var(--border-primary);
padding: var(--space-s);
overflow-x: auto;
}
code {
font-family: "JetBrains Mono", monospace;
font-size: var(--font-size--1);
}
:not(pre) > code {
background-color: var(--bg-secondary);
border: var(--border-primary);
padding-inline: var(--space-3xs);
}

View File

@@ -2,5 +2,10 @@ import { sveltekit } from "@sveltejs/kit/vite";
import { defineConfig } from "vite"; import { defineConfig } from "vite";
export default defineConfig({ export default defineConfig({
plugins: [sveltekit()] plugins: [sveltekit()],
server: {
fs: {
allow: ["."]
}
}
}); });