Finish base template for blog

This commit is contained in:
thiloho
2024-08-28 17:30:32 +02:00
parent 6a5cf76264
commit 4572b7f6ce
7 changed files with 170 additions and 31 deletions

View File

@@ -0,0 +1,106 @@
-- migrate:up
CREATE OR REPLACE VIEW api.website_overview WITH ( security_invoker = ON
) AS
SELECT
w.id,
w.user_id,
w.content_type,
w.title,
s.accent_color_light_theme,
s.accent_color_dark_theme,
s.favicon_image,
h.logo_type,
h.logo_text,
h.logo_image,
ho.main_content,
f.additional_text,
(
SELECT
JSON_AGG(
JSON_BUILD_OBJECT(
'id', a.id, 'title', a.title, 'meta_description', a.meta_description, 'meta_author', a.meta_author, 'cover_image', a.cover_image, 'publication_date', a.publication_date, 'main_content', a.main_content, 'created_at', a.created_at, 'last_modified_at', a.last_modified_at
)
)
FROM
internal.article a
WHERE
a.website_id = w.id
) AS articles,
CASE WHEN w.content_type = 'Docs' THEN
(
SELECT
JSON_OBJECT_AGG(
COALESCE(
category_name, 'Uncategorized'
), articles
)
FROM (
SELECT
dc.category_name,
dc.category_weight AS category_weight,
JSON_AGG(
JSON_BUILD_OBJECT(
'id', a.id, 'title', a.title, 'meta_description', a.meta_description, 'meta_author', a.meta_author, 'cover_image', a.cover_image, 'publication_date', a.publication_date, 'main_content', a.main_content, 'created_at', a.created_at, 'last_modified_at', a.last_modified_at
)
) AS articles
FROM
internal.article a
LEFT JOIN internal.docs_category dc ON a.category = dc.id
WHERE
a.website_id = w.id
GROUP BY
dc.id,
dc.category_name,
dc.category_weight
ORDER BY
category_weight DESC
) AS categorized_articles)
ELSE
NULL
END AS categorized_articles
FROM
internal.website w
JOIN internal.settings s ON w.id = s.website_id
JOIN internal.header h ON w.id = h.website_id
JOIN internal.home ho ON w.id = ho.website_id
JOIN internal.footer f ON w.id = f.website_id;
GRANT SELECT ON api.website_overview TO authenticated_user;
-- migrate:down
DROP VIEW api.website_overview;
CREATE VIEW api.website_overview WITH ( security_invoker = ON
) AS
SELECT
w.id,
w.user_id,
w.content_type,
w.title,
s.accent_color_light_theme,
s.accent_color_dark_theme,
s.favicon_image,
h.logo_type,
h.logo_text,
h.logo_image,
ho.main_content,
f.additional_text,
(
SELECT
JSON_AGG(
JSON_BUILD_OBJECT(
'title', a.title, 'meta_description', a.meta_description, 'meta_author', a.meta_author, 'cover_image', a.cover_image, 'publication_date', a.publication_date, 'main_content', a.main_content
)
)
FROM
internal.article a
WHERE
a.website_id = w.id
) AS articles
FROM
internal.website w
JOIN internal.settings s ON w.id = s.website_id
JOIN internal.header h ON w.id = h.website_id
JOIN internal.home ho ON w.id = ho.website_id
JOIN internal.footer f ON w.id = f.website_id;

View File

@@ -2,11 +2,15 @@
const { const {
logoType, logoType,
logo, logo,
isDocsTemplate = false isDocsTemplate = false,
categorizedArticles = {},
isIndexPage = true
}: { }: {
logoType: "text" | "image"; logoType: "text" | "image";
logo: string; logo: string;
isDocsTemplate?: boolean; isDocsTemplate?: boolean;
categorizedArticles?: { [key: string]: { title: string }[] };
isIndexPage?: boolean;
} = $props(); } = $props();
</script> </script>
@@ -30,9 +34,23 @@
</svg> </svg>
</label> </label>
<ul class="docs-navigation"> <section id="docs-navigation" class="docs-navigation">
<li>nav comes here</li> <ul>
{#each Object.keys(categorizedArticles) as key}
<li>
<strong>{key}</strong>
<ul>
{#each categorizedArticles[key] as { title }}
{@const articleFileName = title.toLowerCase().split(" ").join("-")}
<li>
<a href="{isIndexPage ? './articles' : '.'}/{articleFileName}.html">{title}</a>
</li>
{/each}
</ul> </ul>
</li>
{/each}
</ul>
</section>
{/if} {/if}
<a href="../"> <a href="../">
{#if logoType === "text"} {#if logoType === "text"}

View File

@@ -9,6 +9,7 @@
logoType, logoType,
logo, logo,
mainContent, mainContent,
categorizedArticles,
coverImage, coverImage,
publicationDate, publicationDate,
footerAdditionalText footerAdditionalText
@@ -18,6 +19,7 @@
logoType: "text" | "image"; logoType: "text" | "image";
logo: string; logo: string;
mainContent: string; mainContent: string;
categorizedArticles: { [key: string]: { title: string }[] };
coverImage: string; coverImage: string;
publicationDate: string; publicationDate: string;
footerAdditionalText: string; footerAdditionalText: string;
@@ -26,7 +28,7 @@
<Head {title} {favicon} nestingLevel={1} /> <Head {title} {favicon} nestingLevel={1} />
<Nav {logoType} {logo} isDocsTemplate={true} /> <Nav {logoType} {logo} isDocsTemplate={true} {categorizedArticles} isIndexPage={false} />
<header> <header>
<div class="container"> <div class="container">

View File

@@ -10,6 +10,7 @@
logo, logo,
mainContent, mainContent,
articles, articles,
categorizedArticles,
footerAdditionalText footerAdditionalText
}: { }: {
favicon: string; favicon: string;
@@ -18,13 +19,14 @@
logo: string; logo: string;
mainContent: string; mainContent: string;
articles: { title: string; publication_date: string; meta_description: string }[]; articles: { title: string; publication_date: string; meta_description: string }[];
categorizedArticles: { [key: string]: { title: string }[] };
footerAdditionalText: string; footerAdditionalText: string;
} = $props(); } = $props();
</script> </script>
<Head {title} {favicon} /> <Head {title} {favicon} />
<Nav {logoType} {logo} isDocsTemplate={true} /> <Nav {logoType} {logo} isDocsTemplate={true} {categorizedArticles} />
<header> <header>
<div class="container"> <div class="container">
@@ -35,30 +37,6 @@
<main> <main>
<div class="container"> <div class="container">
{@html mainContent} {@html mainContent}
{#if articles.length > 0}
<section class="articles" id="articles">
<h2>
<a href="#articles">Articles</a>
</h2>
<ul class="unpadded">
{#each articles as article}
{@const articleFileName = article.title.toLowerCase().split(" ").join("-")}
<li>
<p>{article.publication_date}</p>
<p>
<strong>
<a href="./articles/{articleFileName}.html">{article.title}</a>
</strong>
</p>
{#if article.meta_description}
<p>{article.meta_description}</p>
{/if}
</li>
{/each}
</ul>
</section>
{/if}
</div> </div>
</main> </main>

View File

@@ -98,6 +98,7 @@ const generateStaticFiles = async (websiteData: any, isPreview: boolean = true)
: `${API_BASE_PREFIX}/rpc/retrieve_file?id=${websiteData.logo_image}`, : `${API_BASE_PREFIX}/rpc/retrieve_file?id=${websiteData.logo_image}`,
mainContent: md(websiteData.main_content ?? "", false), mainContent: md(websiteData.main_content ?? "", false),
articles: websiteData.articles ?? [], articles: websiteData.articles ?? [],
categorizedArticles: websiteData.categorized_articles ?? [],
footerAdditionalText: md(websiteData.additional_text ?? "") footerAdditionalText: md(websiteData.additional_text ?? "")
} }
})); }));
@@ -169,6 +170,7 @@ const generateStaticFiles = async (websiteData: any, isPreview: boolean = true)
: "", : "",
publicationDate: article.publication_date, publicationDate: article.publication_date,
mainContent: md(article.main_content ?? ""), mainContent: md(article.main_content ?? ""),
categorizedArticles: websiteData.categorized_articles ?? [],
footerAdditionalText: md(websiteData.additional_text ?? "") footerAdditionalText: md(websiteData.additional_text ?? "")
} }
})); }));

View File

@@ -20,7 +20,6 @@
<h2> <h2>
<a href="#publish-website">Publish website</a> <a href="#publish-website">Publish website</a>
</h2> </h2>
{JSON.stringify(data.websiteOverview.articles)}
<p> <p>
The preview area on this page allows you to see exactly how your website will look when it is The preview area on this page allows you to see exactly how your website will look when it is
is published. If you are happy with the results, click the button below and your website will is published. If you are happy with the results, click the button below and your website will

View File

@@ -41,6 +41,40 @@ label[for="toggle-sidebar"] {
place-content: center; place-content: center;
} }
.docs-navigation {
display: none;
position: fixed;
inset-block-start: var(--space-xl);
padding: var(--space-s);
padding-inline-start: 0;
inline-size: 15rem;
block-size: calc(100vh - var(--space-xl));
background-color: var(--bg-primary);
border-inline-end: var(--border-primary);
}
.docs-navigation > ul {
display: flex;
flex-direction: column;
gap: var(--space-s);
}
#toggle-sidebar:checked ~ .docs-navigation {
display: unset;
}
@media (min-width: 1300px) {
.docs-navigation {
display: unset;
inset-inline-start: calc(50% - 37.5ch - var(--space-m));
transform: translateX(-100%);
}
#toggle-sidebar:checked ~ .docs-navigation {
display: none;
}
}
@media (min-width: 1525px) { @media (min-width: 1525px) {
#table-of-contents { #table-of-contents {
position: fixed; position: fixed;