astro-accelerator 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +6 -0
- package/package.json +52 -0
- package/public/js/main.js +45 -0
- package/public/js/modules/animation.js +69 -0
- package/public/js/modules/click-blocks.js +41 -0
- package/public/js/modules/code-blocks.js +59 -0
- package/public/js/modules/events.js +19 -0
- package/public/js/modules/external-links.js +20 -0
- package/public/js/modules/figures.js +37 -0
- package/public/js/modules/focus.js +76 -0
- package/public/js/modules/nav-mobile.js +122 -0
- package/public/js/modules/nav-sticky.js +54 -0
- package/public/js/modules/query.js +41 -0
- package/public/js/modules/resizing.js +43 -0
- package/public/js/modules/string.js +66 -0
- package/public/js/modules/youtube.js +39 -0
- package/public/js/search.js +249 -0
- package/src/data/footer.ts +43 -0
- package/src/data/image-size.mjs +5 -0
- package/src/data/images.mjs +4 -0
- package/src/data/navigation.ts +64 -0
- package/src/layouts/Author.astro +15 -0
- package/src/layouts/Default.astro +15 -0
- package/src/layouts/Redirect.astro +15 -0
- package/src/layouts/Search.astro +15 -0
- package/src/pages/articles/feed.xml.ts +52 -0
- package/src/pages/report/missing-banner.astro +42 -0
- package/src/pages/report/missing-meta.astro +42 -0
- package/src/pages/report/oldest-content.astro +41 -0
- package/src/pages/report/taxonomy.astro +47 -0
- package/src/pages/search.json.ts +43 -0
- package/src/pages/sitemap.xml.ts +36 -0
- package/src/themes/accelerator/components/ArticleList.astro +67 -0
- package/src/themes/accelerator/components/Authors.astro +57 -0
- package/src/themes/accelerator/components/AuthorsMini.astro +37 -0
- package/src/themes/accelerator/components/Breadcrumbs.astro +33 -0
- package/src/themes/accelerator/components/Footer.astro +37 -0
- package/src/themes/accelerator/components/FooterItem.astro +29 -0
- package/src/themes/accelerator/components/Header.astro +46 -0
- package/src/themes/accelerator/components/HtmlHead.astro +49 -0
- package/src/themes/accelerator/components/Navigation.astro +31 -0
- package/src/themes/accelerator/components/NavigationBar.astro +31 -0
- package/src/themes/accelerator/components/NavigationItem.astro +37 -0
- package/src/themes/accelerator/components/Paging.astro +33 -0
- package/src/themes/accelerator/components/Related.astro +88 -0
- package/src/themes/accelerator/components/SkipLinks.astro +25 -0
- package/src/themes/accelerator/components/TableOfContents.astro +32 -0
- package/src/themes/accelerator/components/Taxonomy.astro +49 -0
- package/src/themes/accelerator/layouts/Author.astro +30 -0
- package/src/themes/accelerator/layouts/Default.astro +62 -0
- package/src/themes/accelerator/layouts/Redirect.astro +19 -0
- package/src/themes/accelerator/layouts/Search.astro +43 -0
- package/src/themes/accelerator/utilities/Authors.astro +48 -0
- package/src/themes/accelerator/utilities/Breadcrumbs.astro +27 -0
- package/src/themes/accelerator/utilities/Cache.astro +42 -0
- package/src/themes/accelerator/utilities/DateFormat.astro +25 -0
- package/src/themes/accelerator/utilities/Footer.astro +176 -0
- package/src/themes/accelerator/utilities/Languages.astro +14 -0
- package/src/themes/accelerator/utilities/Markdown.astro +27 -0
- package/src/themes/accelerator/utilities/NavPage.astro +65 -0
- package/src/themes/accelerator/utilities/Navigation.astro +81 -0
- package/src/themes/accelerator/utilities/NavigationTypes.astro +20 -0
- package/src/themes/accelerator/utilities/PageLinks.astro +72 -0
- package/src/themes/accelerator/utilities/PageQueries.astro +71 -0
- package/src/themes/accelerator/utilities/PageTypeFilters.astro +69 -0
- package/src/themes/accelerator/utilities/Taxonomy.astro +112 -0
- package/src/themes/accelerator/utilities/Url.astro +19 -0
- package/src/themes/accelerator/utilities/custom-markdown.mjs +104 -0
- package/src/themes/accelerator/utilities/img.mjs +152 -0
- package/src/themes/accelerator/utilities/language.json +111 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
import t from '@util/language.json';
|
|
3
|
+
import { Lang } from '@util/Languages.astro';
|
|
4
|
+
|
|
5
|
+
import type { NavPage } from '@util/NavigationTypes.astro';
|
|
6
|
+
|
|
7
|
+
// Properties
|
|
8
|
+
type Props = {
|
|
9
|
+
lang: string;
|
|
10
|
+
page: NavPage
|
|
11
|
+
};
|
|
12
|
+
const { lang, page } = Astro.props as Props;
|
|
13
|
+
|
|
14
|
+
// Language
|
|
15
|
+
const _ = Lang(lang);
|
|
16
|
+
|
|
17
|
+
// Logic
|
|
18
|
+
// -
|
|
19
|
+
---
|
|
20
|
+
<div class="footer-column">
|
|
21
|
+
<h2>{ page.title }</h2>
|
|
22
|
+
<ul>
|
|
23
|
+
{ page.children.sort((a, b) => a.order - b.order).map((child) => (
|
|
24
|
+
<li>
|
|
25
|
+
<a href={ child.url } aria-current={ child.ariaCurrent } rel={ child.rel }>{ child.title }</a>
|
|
26
|
+
</li>
|
|
27
|
+
))}
|
|
28
|
+
</ul>
|
|
29
|
+
</div>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { Frontmatter } from '@config';
|
|
3
|
+
|
|
4
|
+
import t from '@util/language.json';
|
|
5
|
+
import { Lang } from '@util/Languages.astro';
|
|
6
|
+
|
|
7
|
+
import { SITE } from '@config';
|
|
8
|
+
import { getPages } from '@util/PageQueries.astro';
|
|
9
|
+
import { addSlashToAddress } from '@util/Url.astro';
|
|
10
|
+
import { isSearch } from '@util/PageTypeFilters.astro';
|
|
11
|
+
|
|
12
|
+
// Properties
|
|
13
|
+
type Props = {
|
|
14
|
+
lang: string;
|
|
15
|
+
frontmatter: Frontmatter
|
|
16
|
+
headings: { depth: number; slug: string; text: string; }[];
|
|
17
|
+
};
|
|
18
|
+
const { lang } = Astro.props as Props;
|
|
19
|
+
|
|
20
|
+
// Language
|
|
21
|
+
const _ = Lang(lang);
|
|
22
|
+
|
|
23
|
+
// Logic
|
|
24
|
+
const search = (await getPages(isSearch))[0] ?? null;
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
<header class="site-header">
|
|
28
|
+
<a href="#site-nav" class="navigation-icon" title={ _(t.header.open_menu) }><svg xmlns="http://www.w3.org/2000/svg"
|
|
29
|
+
width="40" height="40" viewBox="0 0 24 24" stroke-width="1.5"
|
|
30
|
+
fill="none" stroke-linecap="round" stroke-linejoin="round">
|
|
31
|
+
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
|
32
|
+
<line x1="4" y1="6" x2="20" y2="6" />
|
|
33
|
+
<line x1="4" y1="12" x2="20" y2="12" />
|
|
34
|
+
<line x1="4" y1="18" x2="20" y2="18" />
|
|
35
|
+
</svg></a>
|
|
36
|
+
<a href={ (SITE.subfolder ?? '') + '/' } class="site-title" translate="no">{ SITE.title }</a>
|
|
37
|
+
{search != null &&
|
|
38
|
+
<a href={ addSlashToAddress(search.url) } class="search-icon" title={ _(t.header.open_search) }><svg xmlns="http://www.w3.org/2000/svg"
|
|
39
|
+
width="40" height="40" viewBox="0 0 24 24" stroke-width="1"
|
|
40
|
+
fill="none" stroke-linecap="round" stroke-linejoin="round">
|
|
41
|
+
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
|
42
|
+
<circle cx="10" cy="10" r="7" />
|
|
43
|
+
<line x1="21" y1="21" x2="15" y2="15" />
|
|
44
|
+
</svg></a>
|
|
45
|
+
}
|
|
46
|
+
</header>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { SITE, OPEN_GRAPH, HEADER_SCRIPTS, Frontmatter } from '@config';
|
|
3
|
+
import { addSlashToUrl } from '@util/Url.astro';
|
|
4
|
+
|
|
5
|
+
// Properties
|
|
6
|
+
type Props = {
|
|
7
|
+
lang: string;
|
|
8
|
+
frontmatter: Frontmatter
|
|
9
|
+
headings: { depth: number; slug: string; text: string; }[];
|
|
10
|
+
};
|
|
11
|
+
const { frontmatter } = Astro.props;
|
|
12
|
+
|
|
13
|
+
// Logic
|
|
14
|
+
const imageSrc = frontmatter.bannerImage?.src ?? OPEN_GRAPH.image.src;
|
|
15
|
+
const imageAlt = frontmatter.bannerImage?.alt ?? OPEN_GRAPH.image.alt;
|
|
16
|
+
const robots = frontmatter.robots ?? 'index, follow';
|
|
17
|
+
const canonicalImageSrc = new URL(imageSrc, Astro.site);
|
|
18
|
+
const canonicalURL = addSlashToUrl(new URL(Astro.url.pathname, Astro.site + SITE.subfolder));
|
|
19
|
+
---
|
|
20
|
+
<head>
|
|
21
|
+
<meta charset="utf-8" />
|
|
22
|
+
<title>{ frontmatter.title ? `${ frontmatter.title } | ${ SITE.title }` : SITE.title }</title>
|
|
23
|
+
<meta name="robots" content={ 'max-image-preview:large, ' + robots }>
|
|
24
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
25
|
+
<meta name="keywords" content={ frontmatter.keywords }>
|
|
26
|
+
<meta name="description" content={ frontmatter.description }>
|
|
27
|
+
<meta name="theme-color" content={ SITE.themeColor } />
|
|
28
|
+
<link rel="stylesheet" href={ SITE.subfolder + '/css/vars.css' } />
|
|
29
|
+
<link rel="stylesheet" href={ SITE.subfolder + '/css/main.css' } />
|
|
30
|
+
<link rel="canonical" href={ canonicalURL } />
|
|
31
|
+
{SITE.feedUrl &&
|
|
32
|
+
<link rel="alternate" type="application/atom+xml" title={ SITE.title } href={ SITE.feedUrl } />
|
|
33
|
+
}
|
|
34
|
+
<link rel="alternate" href={ SITE.subfolder + '/sitemap.xml' } type="application/rss+xml" />
|
|
35
|
+
<link rel="shortcut icon" href={ SITE.subfolder + '/icons/favicon.ico' } type="image/x-icon" />
|
|
36
|
+
<link rel="apple-touch-icon" href={ SITE.subfolder + '/icons/apple-touch-icon.png' } />
|
|
37
|
+
<meta property="og:type" content="website" />
|
|
38
|
+
<meta property="og:url" content={ canonicalURL } />
|
|
39
|
+
<meta property="og:title" content={ frontmatter.title } />
|
|
40
|
+
<meta property="og:description" content={ frontmatter.description } />
|
|
41
|
+
<meta property="og:image" content={ canonicalImageSrc } />
|
|
42
|
+
<meta property="og:image:alt" content={ imageAlt } />
|
|
43
|
+
<meta name="twitter:card" content="summary_large_image">
|
|
44
|
+
<meta name="twitter:title" content={ frontmatter.title }>
|
|
45
|
+
<meta name="twitter:description" content={ frontmatter.description }>
|
|
46
|
+
<meta name="twitter:image" content={ canonicalImageSrc }>
|
|
47
|
+
<meta name="twitter:image:alt" content={ imageAlt }>
|
|
48
|
+
<Fragment set:html={ HEADER_SCRIPTS }></Fragment>
|
|
49
|
+
</head>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { Frontmatter } from '@config';
|
|
3
|
+
|
|
4
|
+
import t from '@util/language.json';
|
|
5
|
+
import { Lang } from '@util/Languages.astro';
|
|
6
|
+
|
|
7
|
+
import { getMenu } from '@util/Navigation.astro';
|
|
8
|
+
|
|
9
|
+
import NavigationItem from '@components/NavigationItem.astro';
|
|
10
|
+
|
|
11
|
+
// Properties
|
|
12
|
+
type Props = {
|
|
13
|
+
lang: string;
|
|
14
|
+
};
|
|
15
|
+
const { lang } = Astro.props as Props;
|
|
16
|
+
|
|
17
|
+
// Language
|
|
18
|
+
const _ = Lang(lang);
|
|
19
|
+
|
|
20
|
+
// Logic
|
|
21
|
+
const currentUrl = new URL(Astro.request.url);
|
|
22
|
+
const pages = await getMenu(currentUrl);
|
|
23
|
+
---
|
|
24
|
+
<nav class="site-nav" id="site-nav" aria-label={ _(t.aria.site_navigation) }>
|
|
25
|
+
<h2 class="site-nav-title">{ _(t.navigation.title) }</h2>
|
|
26
|
+
<ul>
|
|
27
|
+
{pages.sort((a, b) => a.order - b.order).map((page) => (
|
|
28
|
+
<NavigationItem lang={ lang } page={ page } />
|
|
29
|
+
))}
|
|
30
|
+
</ul>
|
|
31
|
+
</nav>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { Frontmatter } from '@config';
|
|
3
|
+
|
|
4
|
+
import t from '@util/language.json';
|
|
5
|
+
import { Lang } from '@util/Languages.astro';
|
|
6
|
+
|
|
7
|
+
import { getMenu } from '@util/Navigation.astro';
|
|
8
|
+
|
|
9
|
+
import NavigationItem from '@components/NavigationItem.astro';
|
|
10
|
+
|
|
11
|
+
// Properties
|
|
12
|
+
type Props = {
|
|
13
|
+
lang: string;
|
|
14
|
+
};
|
|
15
|
+
const { lang } = Astro.props as Props;
|
|
16
|
+
|
|
17
|
+
// Language
|
|
18
|
+
const _ = Lang(lang);
|
|
19
|
+
|
|
20
|
+
// Logic
|
|
21
|
+
const currentUrl = new URL(Astro.request.url);
|
|
22
|
+
const pages = await getMenu(currentUrl);
|
|
23
|
+
---
|
|
24
|
+
<nav class="site-nav-bar" id="site-nav" aria-label={ _(t.aria.site_navigation) }>
|
|
25
|
+
<h2 class="site-nav-title">{ _(t.navigation.title) }</h2>
|
|
26
|
+
<ul>
|
|
27
|
+
{pages.sort((a, b) => a.order - b.order).map((page) => (
|
|
28
|
+
<li><a href={ page.url }>{ page.title }</a></li>
|
|
29
|
+
))}
|
|
30
|
+
</ul>
|
|
31
|
+
</nav>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
import t from '@util/language.json';
|
|
3
|
+
import { Lang } from '@util/Languages.astro';
|
|
4
|
+
|
|
5
|
+
import type { NavPage } from '@util/NavigationTypes.astro';
|
|
6
|
+
import { addSlashToAddress } from '@util/Url.astro';
|
|
7
|
+
|
|
8
|
+
// Properties
|
|
9
|
+
type Props = {
|
|
10
|
+
lang: string;
|
|
11
|
+
page: NavPage
|
|
12
|
+
};
|
|
13
|
+
const { lang, page } = Astro.props as Props;
|
|
14
|
+
|
|
15
|
+
// Language
|
|
16
|
+
const _ = Lang(lang);
|
|
17
|
+
|
|
18
|
+
// Logic
|
|
19
|
+
// -
|
|
20
|
+
---
|
|
21
|
+
{(page.children.length == 0) && (
|
|
22
|
+
<li>
|
|
23
|
+
<a href={ addSlashToAddress(page.url) } aria-current={ page.ariaCurrent } rel={ page.rel }>{ page.title }</a>
|
|
24
|
+
</li>
|
|
25
|
+
)}
|
|
26
|
+
{(page.children.length > 0) && (
|
|
27
|
+
<li class="has-children">
|
|
28
|
+
<details class="sub-nav" open={ page.isOpen }>
|
|
29
|
+
<summary><span>{ page.section }</span></summary>
|
|
30
|
+
<ul>
|
|
31
|
+
{ page.children.sort((a, b) => a.order - b.order).map((page) => (
|
|
32
|
+
<Astro.self lang={ lang } page={ page } />
|
|
33
|
+
))}
|
|
34
|
+
</ul>
|
|
35
|
+
</details>
|
|
36
|
+
</li>
|
|
37
|
+
)}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { MarkdownInstance, Page } from 'astro';
|
|
3
|
+
import type { Link } from '@util/PageLinks.astro';
|
|
4
|
+
|
|
5
|
+
import t from '@util/language.json';
|
|
6
|
+
import { Lang } from '@util/Languages.astro';
|
|
7
|
+
import { addSlashToAddress } from '@util/Url.astro';
|
|
8
|
+
|
|
9
|
+
// Properties
|
|
10
|
+
type Props = {
|
|
11
|
+
lang: string;
|
|
12
|
+
page: Page<MarkdownInstance<Record<string, any>>>,
|
|
13
|
+
pageLinks: Link[],
|
|
14
|
+
};
|
|
15
|
+
const { lang, page, pageLinks } = Astro.props as Props;
|
|
16
|
+
|
|
17
|
+
// Language
|
|
18
|
+
const _ = Lang(lang);
|
|
19
|
+
|
|
20
|
+
// Logic
|
|
21
|
+
// -
|
|
22
|
+
---
|
|
23
|
+
<nav class="post-paging" aria-label={ _(t.aria.paging) }>
|
|
24
|
+
{page.url.prev
|
|
25
|
+
? <a href={ addSlashToAddress(page.url.prev) }>{ _(t.articles.previous) }</a>
|
|
26
|
+
: <span>{ _(t.articles.previous) }</span>}
|
|
27
|
+
{pageLinks.map((link) => (
|
|
28
|
+
<a href={ addSlashToAddress(link.url) } aria-current={ link.ariaCurrent } class={ link.class }>{ link.title }</a>
|
|
29
|
+
))}
|
|
30
|
+
{page.url.next
|
|
31
|
+
? <a href={ addSlashToAddress(page.url.next) }>{ _(t.articles.next) }</a>
|
|
32
|
+
: <span>{ _(t.articles.next) }</span>}
|
|
33
|
+
</nav>
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { Frontmatter } from '@config';
|
|
3
|
+
import type { MarkdownInstance } from 'astro';
|
|
4
|
+
|
|
5
|
+
import t from '@util/language.json';
|
|
6
|
+
import { Lang } from '@util/Languages.astro';
|
|
7
|
+
import { addSlashToAddress } from '@util/Url.astro';
|
|
8
|
+
import { getImageInfo } from '@util/custom-markdown.mjs'
|
|
9
|
+
import { getPages } from '@util/PageQueries.astro';
|
|
10
|
+
import { isListable, sortByPubDateDesc } from '@util/PageTypeFilters.astro';
|
|
11
|
+
|
|
12
|
+
import AuthorsMini from '@components/AuthorsMini.astro';
|
|
13
|
+
|
|
14
|
+
import { SITE } from '@config';
|
|
15
|
+
|
|
16
|
+
// Properties
|
|
17
|
+
type Props = {
|
|
18
|
+
lang: string;
|
|
19
|
+
frontmatter: Frontmatter
|
|
20
|
+
headings: { depth: number; slug: string; text: string; }[];
|
|
21
|
+
};
|
|
22
|
+
const { lang, frontmatter, headings } = Astro.props as Props;
|
|
23
|
+
|
|
24
|
+
// Language
|
|
25
|
+
const _ = Lang(lang);
|
|
26
|
+
|
|
27
|
+
// Logic
|
|
28
|
+
let posts: MarkdownInstance<Record<string, any>>[] = [];
|
|
29
|
+
const parentCagory = (frontmatter.categories ?? [null])[0];
|
|
30
|
+
|
|
31
|
+
if (parentCagory != null) {
|
|
32
|
+
const allPages = await getPages(isListable)
|
|
33
|
+
const allPosts = allPages
|
|
34
|
+
.filter(p => p.frontmatter.title != frontmatter.title && p.frontmatter.categories && p.frontmatter.categories.includes(parentCagory))
|
|
35
|
+
.sort(sortByPubDateDesc)
|
|
36
|
+
|
|
37
|
+
// One "Most Recent" Post
|
|
38
|
+
if (allPosts.length > 0) {
|
|
39
|
+
posts.push(allPosts[0])
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const olderPost = allPosts.slice(1).filter(p => p.frontmatter.pubDate < frontmatter.pubDate)
|
|
43
|
+
|
|
44
|
+
// One "Older than current" Post
|
|
45
|
+
if (olderPost.length > 0) {
|
|
46
|
+
posts.push(olderPost[0])
|
|
47
|
+
} else if (allPosts.length > 1) {
|
|
48
|
+
posts.push(allPosts[1])
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const articles = posts.map(p => {
|
|
53
|
+
return {
|
|
54
|
+
url: p.url,
|
|
55
|
+
frontmatter: p.frontmatter,
|
|
56
|
+
img: p.frontmatter.bannerImage
|
|
57
|
+
? getImageInfo(p.frontmatter.bannerImage.src, '', SITE.images.listerSize)
|
|
58
|
+
: null
|
|
59
|
+
};
|
|
60
|
+
});
|
|
61
|
+
---
|
|
62
|
+
{articles.length > 0 &&
|
|
63
|
+
<ul class="post-list anim-show-parent">
|
|
64
|
+
{articles.map((post) => (
|
|
65
|
+
<li class="list-item" data-destination={ addSlashToAddress(post.url) } data-image={ (post.frontmatter.bannerImage?.src.length > 0).toString() }>
|
|
66
|
+
<article>
|
|
67
|
+
<div class="list-item-image">
|
|
68
|
+
{post.img && (
|
|
69
|
+
<img
|
|
70
|
+
srcset={ post.img.srcset }
|
|
71
|
+
sizes={ post.img.sizes }
|
|
72
|
+
src={ post.img.src }
|
|
73
|
+
alt={ post.frontmatter.bannerImage.alt }
|
|
74
|
+
class={ post.img.class }
|
|
75
|
+
loading="lazy" />
|
|
76
|
+
)}
|
|
77
|
+
</div>
|
|
78
|
+
<div class="list-item-content">
|
|
79
|
+
<h3>
|
|
80
|
+
<a href={ addSlashToAddress(post.url) }>{ post.frontmatter.title }</a>
|
|
81
|
+
</h3>
|
|
82
|
+
<AuthorsMini lang={ lang } frontmatter={ post.frontmatter as Frontmatter } />
|
|
83
|
+
</div>
|
|
84
|
+
</article>
|
|
85
|
+
</li>
|
|
86
|
+
))}
|
|
87
|
+
</ul>
|
|
88
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { Frontmatter } from '@config';
|
|
3
|
+
|
|
4
|
+
import t from '@util/language.json';
|
|
5
|
+
import { Lang } from '@util/Languages.astro';
|
|
6
|
+
|
|
7
|
+
// Properties
|
|
8
|
+
type Props = {
|
|
9
|
+
lang: string;
|
|
10
|
+
frontmatter: Frontmatter
|
|
11
|
+
headings: { depth: number; slug: string; text: string; }[];
|
|
12
|
+
};
|
|
13
|
+
const { lang } = Astro.props as Props;
|
|
14
|
+
|
|
15
|
+
// Language
|
|
16
|
+
const _ = Lang(lang);
|
|
17
|
+
|
|
18
|
+
// Logic
|
|
19
|
+
// -
|
|
20
|
+
---
|
|
21
|
+
<nav class="skip-links" aria-label={ _(t.aria.skiplinks) } id="site-top">
|
|
22
|
+
<a href="#site-nav">{ _(t.skiplinks.skip_to_navigation) }</a>
|
|
23
|
+
<a href="#site-main">{ _(t.skiplinks.skip_to_content) }</a>
|
|
24
|
+
<a href="#site-footer">{ _(t.skiplinks.skip_to_footer) }</a>
|
|
25
|
+
</nav>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { SITE, Frontmatter } from '@config';
|
|
3
|
+
|
|
4
|
+
import t from '@util/language.json';
|
|
5
|
+
import { Lang } from '@util/Languages.astro';
|
|
6
|
+
|
|
7
|
+
// Properties
|
|
8
|
+
type Props = {
|
|
9
|
+
lang: string;
|
|
10
|
+
frontmatter: Frontmatter;
|
|
11
|
+
headings: { depth: number; slug: string; text: string; }[];
|
|
12
|
+
};
|
|
13
|
+
const { lang, frontmatter, headings } = Astro.props as Props;
|
|
14
|
+
|
|
15
|
+
// Language
|
|
16
|
+
const _ = Lang(lang);
|
|
17
|
+
|
|
18
|
+
// Logic
|
|
19
|
+
// ...
|
|
20
|
+
---
|
|
21
|
+
{headings?.length > 0 &&
|
|
22
|
+
<nav class="page-toc" aria-label={ _(t.aria.toc) }>
|
|
23
|
+
<details>
|
|
24
|
+
<summary>{ _(t.toc.title) }</summary>
|
|
25
|
+
<ol>
|
|
26
|
+
{headings.map((heading) =>(
|
|
27
|
+
<li class={ 'toc-lev-' + heading.depth }><a href={ '#' + heading.slug }>{ heading.text }</a></li>
|
|
28
|
+
))}
|
|
29
|
+
</ol>
|
|
30
|
+
</details>
|
|
31
|
+
</nav>
|
|
32
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { Frontmatter } from '@config';
|
|
3
|
+
|
|
4
|
+
import t from '@util/language.json';
|
|
5
|
+
import { Lang } from '@util/Languages.astro';
|
|
6
|
+
|
|
7
|
+
import { taxonomyLinks } from '@util/Taxonomy.astro';
|
|
8
|
+
|
|
9
|
+
// Properties
|
|
10
|
+
type Props = {
|
|
11
|
+
lang: string;
|
|
12
|
+
frontmatter: Frontmatter;
|
|
13
|
+
};
|
|
14
|
+
const { lang, frontmatter } = Astro.props as Props;
|
|
15
|
+
|
|
16
|
+
// Language
|
|
17
|
+
const _ = Lang(lang);
|
|
18
|
+
|
|
19
|
+
// Logic
|
|
20
|
+
const categories = frontmatter.categories ?? [];
|
|
21
|
+
const tags = frontmatter.tags ?? [];
|
|
22
|
+
|
|
23
|
+
const links = taxonomyLinks(_);
|
|
24
|
+
const hasTaxonomy = (categories.length + tags.length) > 0;
|
|
25
|
+
---
|
|
26
|
+
{hasTaxonomy && (
|
|
27
|
+
<div class="post-taxonomy">
|
|
28
|
+
{tags.length > 0 && (
|
|
29
|
+
<div class="post-tag">
|
|
30
|
+
<h2>{ _(t.articles.tag_title) }: </h2>
|
|
31
|
+
<ul itemprop="keywords">
|
|
32
|
+
{tags.map(tag =>
|
|
33
|
+
<li><a href={ links.getTagLink(tag) }>{ tag }</a></li>
|
|
34
|
+
)}
|
|
35
|
+
</ul>
|
|
36
|
+
</div>
|
|
37
|
+
)}
|
|
38
|
+
{categories.length > 0 && (
|
|
39
|
+
<div class="post-cat">
|
|
40
|
+
<h2>{ _(t.articles.category_title) }: </h2>
|
|
41
|
+
<ul>
|
|
42
|
+
{categories.map(category =>
|
|
43
|
+
<li><a href={ links.getCategoryLink(category) } itemprop="articleSection">{ category }</a></li>
|
|
44
|
+
)}
|
|
45
|
+
</ul>
|
|
46
|
+
</div>
|
|
47
|
+
)}
|
|
48
|
+
</div>
|
|
49
|
+
)}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { SITE, Frontmatter } from '@config';
|
|
3
|
+
|
|
4
|
+
import t from '@util/language.json';
|
|
5
|
+
import { Lang } from '@util/Languages.astro';
|
|
6
|
+
|
|
7
|
+
import { getPages } from '@util/PageQueries.astro';
|
|
8
|
+
|
|
9
|
+
import Default from './Default.astro';
|
|
10
|
+
import ArticleList from '@components/ArticleList.astro';
|
|
11
|
+
|
|
12
|
+
// Properties
|
|
13
|
+
type Props = {
|
|
14
|
+
frontmatter: Frontmatter
|
|
15
|
+
headings: { depth: number; slug: string; text: string; }[];
|
|
16
|
+
}
|
|
17
|
+
const { frontmatter, headings } = Astro.props as Props;
|
|
18
|
+
const lang = frontmatter.lang ?? SITE.default.lang;
|
|
19
|
+
|
|
20
|
+
// Language
|
|
21
|
+
const _ = Lang(lang);
|
|
22
|
+
|
|
23
|
+
// Logic
|
|
24
|
+
const authorPages = await getPages(p => p.frontmatter.authors?.indexOf(frontmatter.id) > -1)
|
|
25
|
+
---
|
|
26
|
+
<Default frontmatter={ frontmatter } headings={ headings }>
|
|
27
|
+
<slot />
|
|
28
|
+
<h2>{ _(t.author.recent_articles) }</h2>
|
|
29
|
+
<ArticleList lang={ lang } posts={ authorPages } />
|
|
30
|
+
</Default>
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { SITE, Frontmatter } from '@config';
|
|
3
|
+
import { getInlineHtmlFrom } from '@util/Markdown.astro';
|
|
4
|
+
|
|
5
|
+
import Head from '@components/HtmlHead.astro';
|
|
6
|
+
import Header from '@components/Header.astro';
|
|
7
|
+
import Footer from '@components/Footer.astro';
|
|
8
|
+
import SkipLinks from '@components/SkipLinks.astro';
|
|
9
|
+
import Breadcrumbs from '@components/Breadcrumbs.astro';
|
|
10
|
+
import Navigation from '@components/Navigation.astro';
|
|
11
|
+
import TableOfContents from '@components/TableOfContents.astro';
|
|
12
|
+
import Authors from '@components/Authors.astro';
|
|
13
|
+
import Taxonomy from '@components/Taxonomy.astro';
|
|
14
|
+
import Related from '@components/Related.astro';
|
|
15
|
+
|
|
16
|
+
type Props = {
|
|
17
|
+
frontmatter: Frontmatter
|
|
18
|
+
headings: { depth: number; slug: string; text: string; }[];
|
|
19
|
+
}
|
|
20
|
+
const { frontmatter, headings } = Astro.props as Props;
|
|
21
|
+
|
|
22
|
+
const lang = frontmatter.lang ?? SITE.default.lang;
|
|
23
|
+
const textDirection = frontmatter.dir ?? SITE.default.dir;
|
|
24
|
+
|
|
25
|
+
const title = await getInlineHtmlFrom(frontmatter.title ?? SITE.title);
|
|
26
|
+
const subtitle = frontmatter.subtitle
|
|
27
|
+
? await getInlineHtmlFrom(frontmatter.subtitle)
|
|
28
|
+
: null;
|
|
29
|
+
|
|
30
|
+
const features = "<script>const site_url = '" + SITE.url + "'; const site_features = '" + JSON.stringify(SITE.featureFlags) + "';</script>";
|
|
31
|
+
---
|
|
32
|
+
<html dir={ textDirection } lang={ lang } class="initial">
|
|
33
|
+
<Head frontmatter={ frontmatter } headings={ headings } lang={ lang } />
|
|
34
|
+
<body>
|
|
35
|
+
<SkipLinks frontmatter={ frontmatter } headings={ headings } lang={ lang } />
|
|
36
|
+
<Header frontmatter={ frontmatter } headings={ headings } lang={ lang } />
|
|
37
|
+
<Breadcrumbs frontmatter={ frontmatter } headings={ headings } lang={ lang } />
|
|
38
|
+
<div class="content-group">
|
|
39
|
+
<Navigation lang={ lang } />
|
|
40
|
+
<main id="site-main">
|
|
41
|
+
<article itemscope itemtype="https://schema.org/Article">
|
|
42
|
+
<header>
|
|
43
|
+
<h1 itemprop="name headline"><Fragment set:html={ title } /></h1>
|
|
44
|
+
{subtitle && (
|
|
45
|
+
<p><Fragment set:html={ subtitle } /></p>
|
|
46
|
+
)}
|
|
47
|
+
</header>
|
|
48
|
+
<div class="page-content anim-show-parent" itemprop="articleBody">
|
|
49
|
+
<TableOfContents frontmatter={ frontmatter } headings={ headings } lang={ lang } />
|
|
50
|
+
<Authors frontmatter={ frontmatter } lang={ lang } />
|
|
51
|
+
<slot />
|
|
52
|
+
<Taxonomy frontmatter={ frontmatter } lang={ lang } />
|
|
53
|
+
<Related frontmatter={ frontmatter } headings={ headings } lang={ lang } />
|
|
54
|
+
</div>
|
|
55
|
+
</article>
|
|
56
|
+
</main>
|
|
57
|
+
</div>
|
|
58
|
+
<Footer frontmatter={ frontmatter } headings={ headings } lang={ lang } />
|
|
59
|
+
<Fragment is:html="true" set:html={ features } />
|
|
60
|
+
<script src={ SITE.subfolder + '/js/main.js' } type="module" async></script>
|
|
61
|
+
</body>
|
|
62
|
+
</html>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { Frontmatter } from '@config';
|
|
3
|
+
|
|
4
|
+
// Properties
|
|
5
|
+
type Props = {
|
|
6
|
+
frontmatter: Frontmatter
|
|
7
|
+
headings: { depth: number; slug: string; text: string; }[];
|
|
8
|
+
}
|
|
9
|
+
const { frontmatter, headings } = Astro.props as Props;
|
|
10
|
+
|
|
11
|
+
const destination = frontmatter.redirect;
|
|
12
|
+
const metaContent = `0; URL=${ destination }`;
|
|
13
|
+
---
|
|
14
|
+
<html>
|
|
15
|
+
<meta charset="utf-8">
|
|
16
|
+
<title>Redirecting to { destination }</title>
|
|
17
|
+
<meta http-equiv="refresh" content={ metaContent }>
|
|
18
|
+
<link rel="canonical" href={ destination }>
|
|
19
|
+
</html>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { SITE, Frontmatter } from '@config';
|
|
3
|
+
|
|
4
|
+
import t from '@util/language.json';
|
|
5
|
+
import { Lang } from '@util/Languages.astro';
|
|
6
|
+
|
|
7
|
+
import Default from './Default.astro';
|
|
8
|
+
|
|
9
|
+
// Properties
|
|
10
|
+
type Props = {
|
|
11
|
+
frontmatter: Frontmatter
|
|
12
|
+
headings: { depth: number; slug: string; text: string; }[];
|
|
13
|
+
}
|
|
14
|
+
const { frontmatter, headings } = Astro.props as Props;
|
|
15
|
+
const lang = frontmatter.lang ?? SITE.default.lang;
|
|
16
|
+
|
|
17
|
+
// Language
|
|
18
|
+
const _ = Lang(lang);
|
|
19
|
+
|
|
20
|
+
// Logic
|
|
21
|
+
const siteUrl = Astro.site ? Astro.site.href : '';
|
|
22
|
+
---
|
|
23
|
+
<Default frontmatter={ frontmatter } headings={ headings }>
|
|
24
|
+
<slot />
|
|
25
|
+
<form method="GET" action={ SITE.search.fallbackUrl ?? 'https://www.google.com/search' } role="search" id="site-search" class="site-search note" autocomplete="off" data-sourcedata={ SITE.subfolder + '/search.json' }>
|
|
26
|
+
<fieldset>
|
|
27
|
+
<input type="hidden" name={ SITE.search.fallbackSite ?? 'q' } value={ 'site:' + siteUrl } />
|
|
28
|
+
<div>
|
|
29
|
+
<label for="site-search-query">{ _(t.search.search_for) }</label>
|
|
30
|
+
<input
|
|
31
|
+
type="text"
|
|
32
|
+
name={ SITE.search.fallbackSite ?? 'q' }
|
|
33
|
+
id="site-search-query"
|
|
34
|
+
spellcheck="true"
|
|
35
|
+
autocomplete="off" />
|
|
36
|
+
<button id="site-search-button" type="submit">{ _(t.search.submit) }</button>
|
|
37
|
+
</div>
|
|
38
|
+
</fieldset>
|
|
39
|
+
</form>
|
|
40
|
+
<div id="site-search-results" data-title={ _(t.search.results_title) } data-emptytitle={ _(t.search.no_results_title) }>
|
|
41
|
+
</div>
|
|
42
|
+
<script src={ SITE.subfolder + '/js/search.js' } type="module" async></script>
|
|
43
|
+
</Default>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { Frontmatter } from '@config';
|
|
3
|
+
import type { MarkdownInstance } from 'astro';
|
|
4
|
+
|
|
5
|
+
import { getPages } from "@util/PageQueries.astro";
|
|
6
|
+
import { isAuthor } from "@util/PageTypeFilters.astro";
|
|
7
|
+
|
|
8
|
+
type BannerImage = { src: string; alt: string } | null;
|
|
9
|
+
type AuthorList = {
|
|
10
|
+
image: BannerImage | null;
|
|
11
|
+
writers: MarkdownInstance<Record<string, any>>[];
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export async function getAuthors () {
|
|
15
|
+
const authors = await getPages(isAuthor);
|
|
16
|
+
return authors;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function getAuthorList (frontmatter: Frontmatter) {
|
|
20
|
+
const authors = await getAuthors();
|
|
21
|
+
|
|
22
|
+
const result: AuthorList = {
|
|
23
|
+
image: null,
|
|
24
|
+
writers: [],
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
(frontmatter.authors ?? []).forEach((a) => {
|
|
28
|
+
const matches = authors.filter((x) => x.frontmatter.id == a);
|
|
29
|
+
|
|
30
|
+
if (matches.length == 0) {
|
|
31
|
+
console.warn("Unknown author", a);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (matches.length > 1) {
|
|
35
|
+
console.warn("Multiple authors with id", a);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (matches.length == 1) {
|
|
39
|
+
result.writers.push(matches[0]);
|
|
40
|
+
if (result.image == null) {
|
|
41
|
+
result.image = matches[0].frontmatter.bannerImage;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
---
|