mirror of
https://github.com/thiloho/archtika.git
synced 2025-11-22 10:51:36 +01:00
Finish base template for blog
This commit is contained in:
@@ -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;
|
||||||
|
|
||||||
@@ -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"}
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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 ?? "")
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user