@yatoday/astro-ui 0.0.2
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 +21 -0
- package/README.md +2 -0
- package/astro.d.ts +31 -0
- package/astro.js +19 -0
- package/components/Analytics/Analytics.astro +15 -0
- package/components/Analytics/AnalyticsGoogle.astro +17 -0
- package/components/Analytics/types.ts +6 -0
- package/components/Background/Background.astro +9 -0
- package/components/Background/Background.svelte +13 -0
- package/components/Background/types.ts +9 -0
- package/components/Card0/Card0.astro +23 -0
- package/components/Card0/card0.ts +6 -0
- package/components/Card0/types.ts +6 -0
- package/components/ConditionalWrapper/ConditionalWrapper.astro +15 -0
- package/components/ConditionalWrapper/ConditionalWrapper.svelte +18 -0
- package/components/ConditionalWrapper/types.ts +10 -0
- package/components/DarkMode/DarkMode.astro +77 -0
- package/components/DarkMode/types.ts +7 -0
- package/components/Layout/Layout.astro +35 -0
- package/components/Layout/types.ts +13 -0
- package/components/Metadata/AstroSeo.astro +40 -0
- package/components/Metadata/Metadata.astro +60 -0
- package/components/Metadata/types.ts +186 -0
- package/components/Metadata/utils/buildTags.ts +380 -0
- package/components/SeoAnalytics/SeoAnalytics.astro +15 -0
- package/components/SeoAnalytics/types.ts +3 -0
- package/components/SeoAnalyticsGoogleProvider/SeoAnalyticsGoogleProvider.astro +17 -0
- package/components/SeoAnalyticsGoogleProvider/types.ts +4 -0
- package/components/SeoAstroSeo/SeoAstroSeo.astro +40 -0
- package/components/SeoAstroSeo/SeoAstroSeo.svelte +3 -0
- package/components/SeoAstroSeo/types.ts +146 -0
- package/components/SeoMetadata/SeoMetadata.astro +8 -0
- package/components/SeoMetadata/types.ts +38 -0
- package/components/SeoSiteVerification/SeoSiteVerification.astro +6 -0
- package/components/SeoSiteVerification/types.ts +3 -0
- package/components/SiteVerification/SiteVerification.astro +6 -0
- package/components/SiteVerification/types.ts +1 -0
- package/components/WidgetWrapper/WidgetWrapper.astro +31 -0
- package/components/WidgetWrapper/WidgetWrapper.ts +6 -0
- package/components/WidgetWrapper/types.ts +10 -0
- package/index.d.ts +180 -0
- package/index.js +6 -0
- package/package.json +99 -0
- package/svelte.d.ts +32 -0
- package/svelte.js +19 -0
- package/utils/buildTags.ts +380 -0
- package/utils/css.ts +39 -0
- package/utils/images-optimization.ts +356 -0
- package/utils/images.ts +138 -0
- package/utils/index.ts +5 -0
- package/utils/permalinks.ts +38 -0
- package/utils/utils.ts +58 -0
- package/vendor-config/index.ts +115 -0
- package/vendor-config/types.d.ts +10 -0
- package/vendor-config/utils/configBuilder.ts +206 -0
- package/vendor-config/utils/loadConfig.ts +16 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Frontendland
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
package/astro.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { AnalyticsProps as YtAnalyticsProps } from './components/Analytics/types'
|
|
2
|
+
import type { BackgroundProps as YtBackgroundProps } from './components/Background/types'
|
|
3
|
+
import type { Card0Props as YtCard0Props } from './components/Card0/types'
|
|
4
|
+
import type { ConditionalWrapperProps as YtConditionalWrapperProps } from './components/ConditionalWrapper/types'
|
|
5
|
+
import type { DarkModeProps as YtDarkModeProps } from './components/DarkMode/types'
|
|
6
|
+
import type { LayoutProps as YtLayoutProps } from './components/Layout/types'
|
|
7
|
+
import type { MetadataProps as YtMetadataProps } from './components/Metadata/types'
|
|
8
|
+
import type { SiteVerificationProps as YtSiteVerificationProps } from './components/SiteVerification/types'
|
|
9
|
+
import type { WidgetWrapperProps as YtWidgetWrapperProps } from './components/WidgetWrapper/types'
|
|
10
|
+
|
|
11
|
+
declare module '@yatoday/astro-ui/astro' {
|
|
12
|
+
export function Analytics(_props: YtAnalyticsProps): any
|
|
13
|
+
export function Background(_props: YtBackgroundProps): any
|
|
14
|
+
export function Card0(_props: YtCard0Props): any
|
|
15
|
+
export function ConditionalWrapper(_props: YtConditionalWrapperProps): any
|
|
16
|
+
export function DarkMode(_props: YtDarkModeProps): any
|
|
17
|
+
export function Layout(_props: YtLayoutProps): any
|
|
18
|
+
export function Metadata(_props: YtMetadataProps): any
|
|
19
|
+
export function SiteVerification(_props: YtSiteVerificationProps): any
|
|
20
|
+
export function WidgetWrapper(_props: YtWidgetWrapperProps): any
|
|
21
|
+
|
|
22
|
+
export type AnalyticsProps = YtAnalyticsProps
|
|
23
|
+
export type BackgroundProps = YtBackgroundProps
|
|
24
|
+
export type Card0Props = YtCard0Props
|
|
25
|
+
export type ConditionalWrapperProps = YtConditionalWrapperProps
|
|
26
|
+
export type DarkModeProps = YtDarkModeProps
|
|
27
|
+
export type LayoutProps = YtLayoutProps
|
|
28
|
+
export type MetadataProps = YtMetadataProps
|
|
29
|
+
export type SiteVerificationProps = YtSiteVerificationProps
|
|
30
|
+
export type WidgetWrapperProps = YtWidgetWrapperProps
|
|
31
|
+
}
|
package/astro.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import AnalyticsComponent from './components/Analytics/Analytics.astro'
|
|
2
|
+
import BackgroundComponent from './components/Background/Background.astro'
|
|
3
|
+
import Card0Component from './components/Card0/Card0.astro'
|
|
4
|
+
import ConditionalWrapperComponent from './components/ConditionalWrapper/ConditionalWrapper.astro'
|
|
5
|
+
import DarkModeComponent from './components/DarkMode/DarkMode.astro'
|
|
6
|
+
import LayoutComponent from './components/Layout/Layout.astro'
|
|
7
|
+
import MetadataComponent from './components/Metadata/Metadata.astro'
|
|
8
|
+
import SiteVerificationComponent from './components/SiteVerification/SiteVerification.astro'
|
|
9
|
+
import WidgetWrapperComponent from './components/WidgetWrapper/WidgetWrapper.astro'
|
|
10
|
+
|
|
11
|
+
export const Analytics = AnalyticsComponent
|
|
12
|
+
export const Background = BackgroundComponent
|
|
13
|
+
export const Card0 = Card0Component
|
|
14
|
+
export const ConditionalWrapper = ConditionalWrapperComponent
|
|
15
|
+
export const DarkMode = DarkModeComponent
|
|
16
|
+
export const Layout = LayoutComponent
|
|
17
|
+
export const Metadata = MetadataComponent
|
|
18
|
+
export const SiteVerification = SiteVerificationComponent
|
|
19
|
+
export const WidgetWrapper = WidgetWrapperComponent
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
//import type { AnalyticsProps as Props } from './types';
|
|
3
|
+
import AnalyticsGoogleProvider from './AnalyticsGoogle.astro';
|
|
4
|
+
|
|
5
|
+
import { ANALYTICS } from 'vendor:config';
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
{
|
|
9
|
+
ANALYTICS?.vendors?.googleAnalytics?.id ? (
|
|
10
|
+
<AnalyticsGoogleProvider
|
|
11
|
+
id={String(ANALYTICS.vendors.googleAnalytics.id)}
|
|
12
|
+
partytown={ANALYTICS?.vendors?.googleAnalytics?.partytown}
|
|
13
|
+
/>
|
|
14
|
+
) : null
|
|
15
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { AnalyticsGoogleProps as Props } from './types';
|
|
3
|
+
|
|
4
|
+
const { id = 'GA_MEASUREMENT_ID', partytown = false } = Astro.props;
|
|
5
|
+
const attrs = partytown ? { type: 'text/partytown' } : {};
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
<script is:inline async src={`https://www.googletagmanager.com/gtag/js?id=${id}`} {...attrs}></script>
|
|
9
|
+
|
|
10
|
+
<script is:inline define:vars={{ id }} {...attrs}>
|
|
11
|
+
window.dataLayer = window.dataLayer || [];
|
|
12
|
+
function gtag() {
|
|
13
|
+
window.dataLayer.push(arguments);
|
|
14
|
+
}
|
|
15
|
+
gtag('js', new Date());
|
|
16
|
+
gtag('config', id);
|
|
17
|
+
</script>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { SvelteBackgroundProps } from './types.ts';
|
|
3
|
+
|
|
4
|
+
const {
|
|
5
|
+
isDark,
|
|
6
|
+
children,
|
|
7
|
+
...rest
|
|
8
|
+
}: SvelteBackgroundProps = $props()
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<div class:list={['absolute inset-0', { 'bg-dark dark:bg-transparent': isDark }]} {...rest}>
|
|
12
|
+
{@render children?.()}
|
|
13
|
+
</div>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { Card0Props as Props } from './types';
|
|
3
|
+
import { twMerge } from 'tailwind-merge';
|
|
4
|
+
|
|
5
|
+
const { as = 'article', classes = {} } = Astro.props;
|
|
6
|
+
|
|
7
|
+
const WrapperTag = as;
|
|
8
|
+
|
|
9
|
+
const { container: containerClass = '', badge: badgeClass = '' } = classes;
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
<WrapperTag
|
|
13
|
+
class={twMerge(
|
|
14
|
+
'relative flex flex-col justify-between gap-6 overflow-hidden rounded-lg border border-input bg-card text-card-foreground py-6 group',
|
|
15
|
+
containerClass
|
|
16
|
+
)}
|
|
17
|
+
>
|
|
18
|
+
<div class={twMerge('absolute', badgeClass)}>
|
|
19
|
+
<slot name="badge" />
|
|
20
|
+
</div>
|
|
21
|
+
<slot name="image" />
|
|
22
|
+
<slot />
|
|
23
|
+
</WrapperTag>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { ConditionalWrapperProps as Props } from './types';
|
|
3
|
+
|
|
4
|
+
const { condition } = Astro.props;
|
|
5
|
+
|
|
6
|
+
const wrapper = await Astro.slots.render('wrapper');
|
|
7
|
+
const children = await Astro.slots.render('default');
|
|
8
|
+
const wrapped = wrapper?.replace('children', children);
|
|
9
|
+
|
|
10
|
+
if (!Astro.slots.has('wrapper')) {
|
|
11
|
+
console.error('Missing wrapper. Add slot="wrapper" to one of the elements.');
|
|
12
|
+
}
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
<Fragment set:html={condition ? wrapped : children} />
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type {SvelteConditionalWrapperProps} from './types'
|
|
3
|
+
|
|
4
|
+
const {
|
|
5
|
+
condition,
|
|
6
|
+
element = 'div',
|
|
7
|
+
children,
|
|
8
|
+
...rest
|
|
9
|
+
}: SvelteConditionalWrapperProps = $props()
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
{#if condition}
|
|
13
|
+
<svelte:element this={element} {...rest}>
|
|
14
|
+
{@render children?.()}
|
|
15
|
+
</svelte:element>
|
|
16
|
+
{:else}
|
|
17
|
+
{@render children?.()}
|
|
18
|
+
{/if}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { Icon } from 'astro-icon/components';
|
|
3
|
+
import { twMerge } from 'tailwind-merge';
|
|
4
|
+
|
|
5
|
+
import type { DarkModeProps as Props } from './types';
|
|
6
|
+
|
|
7
|
+
const {
|
|
8
|
+
label = 'Toggle between Dark and Light mode',
|
|
9
|
+
class:
|
|
10
|
+
className = 'dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-hidden focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-700 rounded-lg text-sm p-2.5',
|
|
11
|
+
iconClass = 'w-6 h-6',
|
|
12
|
+
iconName = 'tabler:sun',
|
|
13
|
+
initialMode = 'system',
|
|
14
|
+
} = Astro.props;
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
{
|
|
18
|
+
!initialMode.endsWith(':only') && (
|
|
19
|
+
<button
|
|
20
|
+
type="button"
|
|
21
|
+
class={twMerge('cursor-pointer inline-flex items-center', className)}
|
|
22
|
+
aria-label={label}
|
|
23
|
+
data-aw-toggle-color-scheme
|
|
24
|
+
>
|
|
25
|
+
<slot>
|
|
26
|
+
<Icon name={iconName} class={iconClass} />
|
|
27
|
+
</slot>
|
|
28
|
+
</button>
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
<script is:inline define:vars={{ mode: initialMode }}>
|
|
33
|
+
// Only run once
|
|
34
|
+
if (!window.darkModeInitialized) {
|
|
35
|
+
window.darkModeInitialized = true;
|
|
36
|
+
|
|
37
|
+
const root = document.documentElement;
|
|
38
|
+
|
|
39
|
+
function applyTheme(theme) {
|
|
40
|
+
if (theme === 'dark') {
|
|
41
|
+
root.classList.add('dark');
|
|
42
|
+
} else {
|
|
43
|
+
root.classList.remove('dark');
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const initialize = function () {
|
|
48
|
+
if ((mode && mode.endsWith(':only')) || (!localStorage.theme && mode !== 'system')) {
|
|
49
|
+
applyTheme(mode.replace(':only', ''));
|
|
50
|
+
} else if (
|
|
51
|
+
localStorage.theme === 'dark' ||
|
|
52
|
+
(!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)
|
|
53
|
+
) {
|
|
54
|
+
applyTheme('dark');
|
|
55
|
+
} else {
|
|
56
|
+
applyTheme('light');
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
initialize();
|
|
60
|
+
|
|
61
|
+
// Add click handlers to all toggles
|
|
62
|
+
document.addEventListener('click', (e) => {
|
|
63
|
+
if (e.target.closest('[data-aw-toggle-color-scheme]')) {
|
|
64
|
+
if (mode.endsWith(':only')) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
root.classList.toggle('dark');
|
|
68
|
+
localStorage.theme = root.classList.contains('dark') ? 'dark' : 'light';
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Listen for view transitions
|
|
73
|
+
document.addEventListener('astro:after-swap', () => {
|
|
74
|
+
initialize();
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
</script>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { getAsset } from '../../utils';
|
|
3
|
+
import SeoMetadata from '../Metadata/Metadata.astro';
|
|
4
|
+
import SeoSiteVerification from '../SiteVerification/SiteVerification.astro';
|
|
5
|
+
import SeoAnalytics from '../Analytics/Analytics.astro';
|
|
6
|
+
import type { LayoutProps as Props } from './types';
|
|
7
|
+
|
|
8
|
+
import { I18N } from 'vendor:config';
|
|
9
|
+
|
|
10
|
+
const { metadata = {} } = Astro.props;
|
|
11
|
+
const { language, textDirection } = I18N;
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<!doctype html>
|
|
15
|
+
<html lang={language} dir={textDirection}>
|
|
16
|
+
<head>
|
|
17
|
+
<meta charset="UTF-8" />
|
|
18
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
19
|
+
|
|
20
|
+
<link rel="sitemap" href={getAsset('/sitemap-index.xml')} />
|
|
21
|
+
<SeoMetadata {...metadata} />
|
|
22
|
+
|
|
23
|
+
<slot name="favicons" />
|
|
24
|
+
<slot name="styles" />
|
|
25
|
+
|
|
26
|
+
<SeoSiteVerification />
|
|
27
|
+
<SeoAnalytics />
|
|
28
|
+
</head>
|
|
29
|
+
|
|
30
|
+
<body class="antialiased bg-background text-foreground tracking-tight">
|
|
31
|
+
<slot />
|
|
32
|
+
|
|
33
|
+
<slot name="scripts" />
|
|
34
|
+
</body>
|
|
35
|
+
</html>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { MetaData, MetaDataOpenGraph, MetaDataRobots, MetaDataTwitter } from '~/components/SeoMetadata/types';
|
|
2
|
+
|
|
3
|
+
export type LayoutProps = {
|
|
4
|
+
title?: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
ignoreTitleTemplate?: boolean;
|
|
7
|
+
canonical?: string;
|
|
8
|
+
|
|
9
|
+
robots?: MetaDataRobots;
|
|
10
|
+
openGraph?: MetaDataOpenGraph;
|
|
11
|
+
twitter?: MetaDataTwitter;
|
|
12
|
+
metadata?: MetaData;
|
|
13
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { AstroSeoProps as Props } from './types';
|
|
3
|
+
import { buildTags } from './utils/buildTags';
|
|
4
|
+
|
|
5
|
+
const {
|
|
6
|
+
title,
|
|
7
|
+
titleTemplate,
|
|
8
|
+
noindex,
|
|
9
|
+
nofollow,
|
|
10
|
+
robotsProps,
|
|
11
|
+
description,
|
|
12
|
+
canonical,
|
|
13
|
+
mobileAlternate,
|
|
14
|
+
languageAlternates,
|
|
15
|
+
openGraph,
|
|
16
|
+
facebook,
|
|
17
|
+
twitter,
|
|
18
|
+
additionalMetaTags,
|
|
19
|
+
additionalLinkTags,
|
|
20
|
+
} = Astro.props;
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
<Fragment
|
|
24
|
+
set:html={buildTags({
|
|
25
|
+
title,
|
|
26
|
+
titleTemplate,
|
|
27
|
+
noindex,
|
|
28
|
+
nofollow,
|
|
29
|
+
robotsProps,
|
|
30
|
+
description,
|
|
31
|
+
canonical,
|
|
32
|
+
mobileAlternate,
|
|
33
|
+
languageAlternates,
|
|
34
|
+
openGraph,
|
|
35
|
+
facebook,
|
|
36
|
+
twitter,
|
|
37
|
+
additionalMetaTags,
|
|
38
|
+
additionalLinkTags,
|
|
39
|
+
})}
|
|
40
|
+
/>
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { AstroSeoProps, MetadataProps as Props } from './types';
|
|
3
|
+
import AstroSeo from './AstroSeo.astro';
|
|
4
|
+
import { adaptOpenGraphImages, getCanonical } from '../../utils';
|
|
5
|
+
|
|
6
|
+
import merge from 'lodash.merge';
|
|
7
|
+
import { I18N, METADATA, SITE } from 'vendor:config';
|
|
8
|
+
|
|
9
|
+
const {
|
|
10
|
+
title,
|
|
11
|
+
ignoreTitleTemplate = false,
|
|
12
|
+
canonical = String(getCanonical(String(Astro.url.pathname))),
|
|
13
|
+
robots = {},
|
|
14
|
+
description,
|
|
15
|
+
openGraph = {},
|
|
16
|
+
twitter = {},
|
|
17
|
+
} = Astro.props;
|
|
18
|
+
|
|
19
|
+
const seoProps: AstroSeoProps = merge(
|
|
20
|
+
{
|
|
21
|
+
title: '',
|
|
22
|
+
titleTemplate: '%s',
|
|
23
|
+
canonical,
|
|
24
|
+
noindex: true,
|
|
25
|
+
nofollow: true,
|
|
26
|
+
description: undefined,
|
|
27
|
+
openGraph: {
|
|
28
|
+
url: canonical,
|
|
29
|
+
site_name: SITE?.name,
|
|
30
|
+
images: [],
|
|
31
|
+
locale: I18N?.language || 'en',
|
|
32
|
+
type: 'website',
|
|
33
|
+
},
|
|
34
|
+
twitter: {
|
|
35
|
+
cardType: openGraph?.images?.length ? 'summary_large_image' : 'summary',
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
title: METADATA?.title?.default,
|
|
40
|
+
titleTemplate: METADATA?.title?.template,
|
|
41
|
+
noindex: typeof METADATA?.robots?.index !== 'undefined' ? !METADATA.robots.index : undefined,
|
|
42
|
+
nofollow: typeof METADATA?.robots?.follow !== 'undefined' ? !METADATA.robots.follow : undefined,
|
|
43
|
+
description: METADATA?.description,
|
|
44
|
+
openGraph: METADATA?.openGraph,
|
|
45
|
+
twitter: METADATA?.twitter,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
title,
|
|
49
|
+
titleTemplate: ignoreTitleTemplate ? '%s' : undefined,
|
|
50
|
+
canonical,
|
|
51
|
+
noindex: typeof robots?.index !== 'undefined' ? !robots.index : undefined,
|
|
52
|
+
nofollow: typeof robots?.follow !== 'undefined' ? !robots.follow : undefined,
|
|
53
|
+
description,
|
|
54
|
+
openGraph: { url: canonical, ...openGraph },
|
|
55
|
+
twitter,
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
<AstroSeo {...{ ...seoProps, openGraph: await adaptOpenGraphImages(seoProps?.openGraph, Astro.site) }} />
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
export type MetadataProps = {
|
|
2
|
+
dontUseTitleTemplate?: boolean;
|
|
3
|
+
} extends MetaData
|
|
4
|
+
? never
|
|
5
|
+
: MetaData;
|
|
6
|
+
|
|
7
|
+
export interface MetaData {
|
|
8
|
+
title?: string;
|
|
9
|
+
ignoreTitleTemplate?: boolean;
|
|
10
|
+
canonical?: string;
|
|
11
|
+
robots?: MetaDataRobots;
|
|
12
|
+
description?: string;
|
|
13
|
+
openGraph?: MetaDataOpenGraph;
|
|
14
|
+
twitter?: MetaDataTwitter;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface MetaDataRobots {
|
|
18
|
+
index?: boolean;
|
|
19
|
+
follow?: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface MetaDataImage {
|
|
23
|
+
url: string;
|
|
24
|
+
width?: number;
|
|
25
|
+
height?: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface MetaDataOpenGraph {
|
|
29
|
+
url?: string;
|
|
30
|
+
siteName?: string;
|
|
31
|
+
images?: Array<MetaDataImage>;
|
|
32
|
+
locale?: string;
|
|
33
|
+
type?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface MetaDataTwitter {
|
|
37
|
+
handle?: string;
|
|
38
|
+
site?: string;
|
|
39
|
+
cardType?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type AstroSeoProps = {
|
|
43
|
+
title?: string;
|
|
44
|
+
titleTemplate?: string;
|
|
45
|
+
noindex?: boolean;
|
|
46
|
+
nofollow?: boolean;
|
|
47
|
+
robotsProps?: AdditionalRobotsProps;
|
|
48
|
+
description?: string;
|
|
49
|
+
canonical?: string;
|
|
50
|
+
mobileAlternate?: MobileAlternate;
|
|
51
|
+
languageAlternates?: ReadonlyArray<LanguageAlternate>;
|
|
52
|
+
openGraph?: OpenGraph;
|
|
53
|
+
facebook?: { appId: string };
|
|
54
|
+
twitter?: Twitter;
|
|
55
|
+
additionalMetaTags?: ReadonlyArray<MetaTag>;
|
|
56
|
+
additionalLinkTags?: ReadonlyArray<LinkTag>;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export interface OpenGraphMedia {
|
|
60
|
+
url: string;
|
|
61
|
+
width?: number;
|
|
62
|
+
height?: number;
|
|
63
|
+
alt?: string;
|
|
64
|
+
type?: string;
|
|
65
|
+
secureUrl?: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface AdditionalRobotsProps {
|
|
69
|
+
nosnippet?: boolean;
|
|
70
|
+
maxSnippet?: number;
|
|
71
|
+
maxImagePreview?: ImagePrevSize;
|
|
72
|
+
maxVideoPreview?: number;
|
|
73
|
+
noarchive?: boolean;
|
|
74
|
+
unavailableAfter?: string;
|
|
75
|
+
noimageindex?: boolean;
|
|
76
|
+
notranslate?: boolean;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export type ImagePrevSize = 'none' | 'standard' | 'large';
|
|
80
|
+
|
|
81
|
+
export interface OpenGraphVideoActors {
|
|
82
|
+
profile: string;
|
|
83
|
+
role?: string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface OpenGraph {
|
|
87
|
+
url?: string;
|
|
88
|
+
type?: string;
|
|
89
|
+
title?: string;
|
|
90
|
+
description?: string;
|
|
91
|
+
images?: ReadonlyArray<OpenGraphMedia>;
|
|
92
|
+
videos?: ReadonlyArray<OpenGraphMedia>;
|
|
93
|
+
defaultImageHeight?: number;
|
|
94
|
+
defaultImageWidth?: number;
|
|
95
|
+
locale?: string;
|
|
96
|
+
site_name?: string;
|
|
97
|
+
profile?: OpenGraphProfile;
|
|
98
|
+
book?: OpenGraphBook;
|
|
99
|
+
article?: OpenGraphArticle;
|
|
100
|
+
video?: OpenGraphVideo;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface OpenGraphProfile {
|
|
104
|
+
firstName?: string;
|
|
105
|
+
lastName?: string;
|
|
106
|
+
username?: string;
|
|
107
|
+
gender?: string;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export interface OpenGraphBook {
|
|
111
|
+
authors?: ReadonlyArray<string>;
|
|
112
|
+
isbn?: string;
|
|
113
|
+
releaseDate?: string;
|
|
114
|
+
tags?: ReadonlyArray<string>;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export interface OpenGraphArticle {
|
|
118
|
+
publishedTime?: string;
|
|
119
|
+
modifiedTime?: string;
|
|
120
|
+
expirationTime?: string;
|
|
121
|
+
|
|
122
|
+
authors?: ReadonlyArray<string>;
|
|
123
|
+
section?: string;
|
|
124
|
+
tags?: ReadonlyArray<string>;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export interface OpenGraphVideo {
|
|
128
|
+
actors?: ReadonlyArray<OpenGraphVideoActors>;
|
|
129
|
+
directors?: ReadonlyArray<string>;
|
|
130
|
+
writers?: ReadonlyArray<string>;
|
|
131
|
+
duration?: number;
|
|
132
|
+
releaseDate?: string;
|
|
133
|
+
tags?: ReadonlyArray<string>;
|
|
134
|
+
series?: string;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export interface Twitter {
|
|
138
|
+
handle?: string;
|
|
139
|
+
site?: string;
|
|
140
|
+
cardType?: string;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
interface MobileAlternate {
|
|
144
|
+
media: string;
|
|
145
|
+
href: string;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
interface LanguageAlternate {
|
|
149
|
+
hreflang: string;
|
|
150
|
+
href: string;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
interface LinkTag {
|
|
154
|
+
rel: string;
|
|
155
|
+
href: string;
|
|
156
|
+
sizes?: string;
|
|
157
|
+
media?: string;
|
|
158
|
+
type?: string;
|
|
159
|
+
color?: string;
|
|
160
|
+
as?: string;
|
|
161
|
+
crossOrigin?: string;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export interface BaseMetaTag {
|
|
165
|
+
content: string;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export interface HTML5MetaTag extends BaseMetaTag {
|
|
169
|
+
name: string;
|
|
170
|
+
property?: undefined;
|
|
171
|
+
httpEquiv?: undefined;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export interface RDFaMetaTag extends BaseMetaTag {
|
|
175
|
+
property: string;
|
|
176
|
+
name?: undefined;
|
|
177
|
+
httpEquiv?: undefined;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export interface HTTPEquivMetaTag extends BaseMetaTag {
|
|
181
|
+
httpEquiv: 'content-security-policy' | 'content-type' | 'default-style' | 'x-ua-compatible' | 'refresh';
|
|
182
|
+
name?: undefined;
|
|
183
|
+
property?: undefined;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export type MetaTag = HTML5MetaTag | RDFaMetaTag | HTTPEquivMetaTag;
|