@levino/shipyard-base 0.1.0
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/lib/components/Footer.astro +26 -0
- package/lib/components/GlobalDesktopNavigation.astro +71 -0
- package/lib/components/LocalNavigation.astro +20 -0
- package/lib/components/SidebarElement.astro +26 -0
- package/lib/components/SidebarNavigation.astro +36 -0
- package/lib/components/TableOfContents.astro +23 -0
- package/lib/components/types.d.ts +6 -0
- package/lib/components/types.js +2 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.js +27 -0
- package/lib/layouts/Footer.astro +14 -0
- package/lib/layouts/Page.astro +86 -0
- package/lib/layouts/Splash.astro +7 -0
- package/lib/schemas/config.d.ts +15 -0
- package/lib/schemas/config.js +2 -0
- package/lib/tools/cn.d.ts +2 -0
- package/lib/tools/cn.js +10 -0
- package/lib/types.d.ts +7 -0
- package/lib/types.js +31 -0
- package/package.json +31 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
interface FooterProps {
|
|
3
|
+
links: {
|
|
4
|
+
label: string;
|
|
5
|
+
href: string;
|
|
6
|
+
}[];
|
|
7
|
+
copyright: {
|
|
8
|
+
label: string;
|
|
9
|
+
href: string;
|
|
10
|
+
year: number;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const { links, copyright } = Astro.props as FooterProps;
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
<footer class="flex w-full items-center justify-between px-6 py-4 text-sm font-medium">
|
|
18
|
+
<a href={copyright.href} target="_blank">
|
|
19
|
+
© {copyright.label}, {copyright.year}
|
|
20
|
+
</a>
|
|
21
|
+
{links.map(({ label, href }) => (
|
|
22
|
+
<a href={href}>
|
|
23
|
+
{label}
|
|
24
|
+
</a>
|
|
25
|
+
))}
|
|
26
|
+
</footer>
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { Config } from '../schemas/config';
|
|
3
|
+
import { cn } from '../tools/cn';
|
|
4
|
+
|
|
5
|
+
type Props = Pick<Config, 'brand' | 'navigation'> & { showBrand: boolean };
|
|
6
|
+
|
|
7
|
+
const { brand, navigation, showBrand = false } = Astro.props as Props;
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
<div class="navbar z-10 bg-base-100">
|
|
11
|
+
<span
|
|
12
|
+
class="tooltip tooltip-bottom before:text-xs before:content-[attr(data-tip)]"
|
|
13
|
+
data-tip="Menu"
|
|
14
|
+
>
|
|
15
|
+
<label
|
|
16
|
+
aria-label="Open menu"
|
|
17
|
+
for="drawer"
|
|
18
|
+
class="btn btn-square btn-ghost drawer-button lg:hidden"
|
|
19
|
+
>
|
|
20
|
+
<svg
|
|
21
|
+
width="20"
|
|
22
|
+
height="20"
|
|
23
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
24
|
+
fill="none"
|
|
25
|
+
viewBox="0 0 24 24"
|
|
26
|
+
class="inline-block h-5 w-5 stroke-current md:h-6 md:w-6"
|
|
27
|
+
>
|
|
28
|
+
<path
|
|
29
|
+
stroke-linecap="round"
|
|
30
|
+
stroke-linejoin="round"
|
|
31
|
+
stroke-width="2"
|
|
32
|
+
d="M4 6h16M4 12h16M4 18h16"
|
|
33
|
+
></path>
|
|
34
|
+
</svg>
|
|
35
|
+
</label>
|
|
36
|
+
</span>
|
|
37
|
+
<div class="flex-1">
|
|
38
|
+
<a
|
|
39
|
+
href="/"
|
|
40
|
+
class={cn('btn btn-ghost text-xl', {
|
|
41
|
+
'md:hidden': !showBrand,
|
|
42
|
+
})}
|
|
43
|
+
>
|
|
44
|
+
{brand}
|
|
45
|
+
</a>
|
|
46
|
+
</div>
|
|
47
|
+
<div class="hidden flex-none lg:flex">
|
|
48
|
+
<ul class="menu menu-horizontal px-1">
|
|
49
|
+
{Object.entries(navigation).map(([key, entry]) =>
|
|
50
|
+
entry.subEntry ? (
|
|
51
|
+
<li>
|
|
52
|
+
<details>
|
|
53
|
+
<summary>{entry.label ?? key}</summary>
|
|
54
|
+
<ul class="rounded-t-none bg-base-100 p-2">
|
|
55
|
+
{Object.entries(entry.subEntry).map(([key, entry]) => (
|
|
56
|
+
<li>
|
|
57
|
+
<a href={entry.href}>{entry.label ?? key}</a>
|
|
58
|
+
</li>
|
|
59
|
+
))}
|
|
60
|
+
</ul>
|
|
61
|
+
</details>
|
|
62
|
+
</li>
|
|
63
|
+
) : (
|
|
64
|
+
<li>
|
|
65
|
+
<a href={entry.href}>{entry.label ?? key}</a>
|
|
66
|
+
</li>
|
|
67
|
+
)
|
|
68
|
+
)}
|
|
69
|
+
</ul>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
import SidebarElement from './SidebarElement.astro';
|
|
3
|
+
|
|
4
|
+
export type Entry = Record<
|
|
5
|
+
string,
|
|
6
|
+
{
|
|
7
|
+
label?: string;
|
|
8
|
+
href?: string;
|
|
9
|
+
subEntry?: Entry;
|
|
10
|
+
}
|
|
11
|
+
>;
|
|
12
|
+
|
|
13
|
+
interface SidebarProps {
|
|
14
|
+
entry: Entry;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const { entry } = Astro.props as SidebarProps;
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
<SidebarElement entry={entry} />
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { Entry } from './types';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
entry: Entry;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const { entry } = Astro.props;
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
{Object.entries(entry).map(([key, entry]) => {
|
|
13
|
+
const label = entry.label ?? key;
|
|
14
|
+
return (
|
|
15
|
+
<li>
|
|
16
|
+
{entry.href
|
|
17
|
+
? <a href={entry.href}>{label}</a>
|
|
18
|
+
: <span class='menu-title'>{label}</span>}
|
|
19
|
+
{entry.subEntry ? (
|
|
20
|
+
<ul>
|
|
21
|
+
<Astro.self entry={entry.subEntry} />
|
|
22
|
+
</ul>
|
|
23
|
+
) : null}
|
|
24
|
+
</li>
|
|
25
|
+
)
|
|
26
|
+
})}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { cn } from '../tools/cn';
|
|
3
|
+
import SidebarElement from './SidebarElement.astro';
|
|
4
|
+
import type { Entry } from './types';
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
local?: Entry;
|
|
8
|
+
global: Entry;
|
|
9
|
+
brand: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
const { local, global, brand } = Astro.props;
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
<ul class={cn('menu min-h-screen w-56 bg-base-100', { 'md:hidden': !local })}>
|
|
17
|
+
<div>
|
|
18
|
+
<a href="/" class="btn btn-ghost mb-2 text-xl">
|
|
19
|
+
{brand}
|
|
20
|
+
</a>
|
|
21
|
+
</div>
|
|
22
|
+
<div class="block md:hidden">
|
|
23
|
+
<li>
|
|
24
|
+
{local ? (
|
|
25
|
+
<details>
|
|
26
|
+
<summary>Main menu</summary>
|
|
27
|
+
<SidebarElement entry={global} />
|
|
28
|
+
</details>
|
|
29
|
+
) : (
|
|
30
|
+
<SidebarElement entry={global} />
|
|
31
|
+
)}
|
|
32
|
+
</li>
|
|
33
|
+
<div class={cn('divider my-1 block md:hidden', { hidden: !local })} />
|
|
34
|
+
</div>
|
|
35
|
+
{local && <SidebarElement entry={local} />}
|
|
36
|
+
</ul>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
interface Link {
|
|
3
|
+
depth: number;
|
|
4
|
+
text: string;
|
|
5
|
+
slug: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface TableOfContentsProps {
|
|
9
|
+
links: Link[];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const { links } = Astro.props as TableOfContentsProps;
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
<div class="fixed right-0 h-full lg:h-auto lg:overflow-y-visible">
|
|
16
|
+
<div class="w-128 sticky" aria-label="Auf dieser Seite">
|
|
17
|
+
{links.map((link, key) => (
|
|
18
|
+
<a href={`#${link.slug}`}>
|
|
19
|
+
{link.text}
|
|
20
|
+
</a>
|
|
21
|
+
))}
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
package/lib/index.d.ts
ADDED
package/lib/index.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const shipyardConfigId = 'virtual:shipyard/config';
|
|
4
|
+
const resolveId = {
|
|
5
|
+
[shipyardConfigId]: `${shipyardConfigId}`,
|
|
6
|
+
};
|
|
7
|
+
const load = (config) => ({
|
|
8
|
+
[shipyardConfigId]: `export default ${JSON.stringify(config)}`,
|
|
9
|
+
});
|
|
10
|
+
exports.default = (config) => ({
|
|
11
|
+
name: 'shipyard',
|
|
12
|
+
hooks: {
|
|
13
|
+
'astro:config:setup': ({ updateConfig }) => {
|
|
14
|
+
updateConfig({
|
|
15
|
+
vite: {
|
|
16
|
+
plugins: [
|
|
17
|
+
{
|
|
18
|
+
name: 'shipyard',
|
|
19
|
+
resolveId: (id) => resolveId[id],
|
|
20
|
+
load: (id) => load(config)[id],
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
import FooterComponent from '@levino/shipyard-base/components/Footer.astro'
|
|
3
|
+
|
|
4
|
+
const locale = Astro.currentLocale
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
<FooterComponent
|
|
8
|
+
links={[{ href: `/${locale}/imprint`, label: 'Impressum' }]}
|
|
9
|
+
copyright={{
|
|
10
|
+
href: 'https://github.com/levino',
|
|
11
|
+
label: 'Levin Keller',
|
|
12
|
+
year: 2023,
|
|
13
|
+
}}
|
|
14
|
+
/>
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
import Footer from './Footer.astro'
|
|
3
|
+
import '../globals.css'
|
|
4
|
+
import config from 'virtual:shipyard/config'
|
|
5
|
+
import GlobalDesktopNavigation from '../components/GlobalDesktopNavigation.astro'
|
|
6
|
+
import type { NavigationTree, NavigationEntry } from '@/schemas/config'
|
|
7
|
+
import { mapObjIndexed } from 'ramda'
|
|
8
|
+
import SidebarNavigation from '../components/SidebarNavigation.astro'
|
|
9
|
+
|
|
10
|
+
type Props = {
|
|
11
|
+
frontmatter?: {
|
|
12
|
+
title?: string
|
|
13
|
+
description?: string
|
|
14
|
+
sidebarNavigation?: NavigationTree
|
|
15
|
+
}
|
|
16
|
+
} & {
|
|
17
|
+
title?: string
|
|
18
|
+
description?: string
|
|
19
|
+
sidebarNavigation?: NavigationTree
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const locale = Astro.currentLocale || 'de'
|
|
23
|
+
const currentPath = Astro.url.pathname
|
|
24
|
+
const props = Astro.props.frontmatter || Astro.props
|
|
25
|
+
|
|
26
|
+
const withLocale = (locale: string) => (path: string) => `/${locale}${path}`
|
|
27
|
+
const withCurrentLocale = withLocale(locale)
|
|
28
|
+
const applyLocaleAndSetActive: (navigation: NavigationTree) => NavigationTree =
|
|
29
|
+
mapObjIndexed((entry: NavigationEntry) => ({
|
|
30
|
+
...entry,
|
|
31
|
+
...(entry.href ? { href: withCurrentLocale(entry.href) } : {}),
|
|
32
|
+
active: entry.href === currentPath,
|
|
33
|
+
...(entry.subEntry
|
|
34
|
+
? { subEntry: applyLocaleAndSetActive(entry.subEntry) }
|
|
35
|
+
: {}),
|
|
36
|
+
}))
|
|
37
|
+
|
|
38
|
+
const navigation = applyLocaleAndSetActive(config.navigation)
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
<html>
|
|
42
|
+
<head>
|
|
43
|
+
<meta charset="utf-8" />
|
|
44
|
+
<link rel="sitemap" href="/sitemap-index.xml" />
|
|
45
|
+
<title>
|
|
46
|
+
{
|
|
47
|
+
config.meta.title
|
|
48
|
+
? `Levin Keller - ${config.meta.title}`
|
|
49
|
+
: 'Levin Keller'
|
|
50
|
+
}
|
|
51
|
+
</title>
|
|
52
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
53
|
+
</head>
|
|
54
|
+
<body>
|
|
55
|
+
<div class="drawer lg:drawer-open">
|
|
56
|
+
<input id="drawer" type="checkbox" class="drawer-toggle" />
|
|
57
|
+
<div class="drawer-content">
|
|
58
|
+
<div class="flex min-h-screen flex-col">
|
|
59
|
+
<GlobalDesktopNavigation
|
|
60
|
+
showBrand={!props.sidebarNavigation}
|
|
61
|
+
brand={config.brand}
|
|
62
|
+
navigation={navigation}
|
|
63
|
+
/>
|
|
64
|
+
<div class="grow">
|
|
65
|
+
<div class="mx-auto px-4">
|
|
66
|
+
<slot />
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
<Footer />
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
<div class="drawer-side z-40">
|
|
74
|
+
<label for="drawer" aria-label="close sidebar" class="drawer-overlay"
|
|
75
|
+
></label>
|
|
76
|
+
<div>
|
|
77
|
+
<SidebarNavigation
|
|
78
|
+
brand={config.brand}
|
|
79
|
+
global={navigation}
|
|
80
|
+
local={props.sidebarNavigation}
|
|
81
|
+
/>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
</body>
|
|
86
|
+
</html>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface NavigationEntry {
|
|
2
|
+
label?: string;
|
|
3
|
+
href?: string;
|
|
4
|
+
subEntry?: NavigationTree;
|
|
5
|
+
active?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export type NavigationTree = Record<string, NavigationEntry>;
|
|
8
|
+
export type Config = {
|
|
9
|
+
brand: string;
|
|
10
|
+
navigation: NavigationTree;
|
|
11
|
+
meta: {
|
|
12
|
+
title: string;
|
|
13
|
+
description: string;
|
|
14
|
+
};
|
|
15
|
+
};
|
package/lib/tools/cn.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.cn = void 0;
|
|
7
|
+
const clsx_1 = __importDefault(require("clsx"));
|
|
8
|
+
const tailwind_merge_1 = require("tailwind-merge");
|
|
9
|
+
const cn = (...classes) => (0, tailwind_merge_1.twMerge)((0, clsx_1.default)(...classes));
|
|
10
|
+
exports.cn = cn;
|
package/lib/types.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface LinkData {
|
|
2
|
+
href: string;
|
|
3
|
+
label: string;
|
|
4
|
+
active: boolean;
|
|
5
|
+
}
|
|
6
|
+
export declare const MONTHS_EN: readonly ["january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december"];
|
|
7
|
+
export declare const MONTHS_DE: readonly ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"];
|
package/lib/types.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MONTHS_DE = exports.MONTHS_EN = void 0;
|
|
4
|
+
exports.MONTHS_EN = [
|
|
5
|
+
'january',
|
|
6
|
+
'february',
|
|
7
|
+
'march',
|
|
8
|
+
'april',
|
|
9
|
+
'may',
|
|
10
|
+
'june',
|
|
11
|
+
'july',
|
|
12
|
+
'august',
|
|
13
|
+
'september',
|
|
14
|
+
'october',
|
|
15
|
+
'november',
|
|
16
|
+
'december',
|
|
17
|
+
];
|
|
18
|
+
exports.MONTHS_DE = [
|
|
19
|
+
'Januar',
|
|
20
|
+
'Februar',
|
|
21
|
+
'März',
|
|
22
|
+
'April',
|
|
23
|
+
'Mai',
|
|
24
|
+
'Juni',
|
|
25
|
+
'Juli',
|
|
26
|
+
'August',
|
|
27
|
+
'September',
|
|
28
|
+
'Oktober',
|
|
29
|
+
'November',
|
|
30
|
+
'Dezember',
|
|
31
|
+
];
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@levino/shipyard-base",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"peerDependencies": {
|
|
7
|
+
"astro": "^5",
|
|
8
|
+
"daisyui": "^4",
|
|
9
|
+
"tailwindcss": "^3",
|
|
10
|
+
"@tailwindcss/typography": "^0.5.10"
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc -p tsconfig.build.json && rsync -avm --include='*/' --include='*.astro' --exclude='*' ./src/ ./lib/"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"lib"
|
|
17
|
+
],
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@tailwindcss/typography": "^0.5.10",
|
|
20
|
+
"@types/ramda": "^0.29.9",
|
|
21
|
+
"daisyui": "^4.6.0",
|
|
22
|
+
"tailwindcss": "^3.4.0",
|
|
23
|
+
"typescript": "^5.2.2",
|
|
24
|
+
"vite": "^4"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"clsx": "^2.1.0",
|
|
28
|
+
"ramda": "^0.29.1",
|
|
29
|
+
"tailwind-merge": "^2.2.0"
|
|
30
|
+
}
|
|
31
|
+
}
|