Simplify folders and more typescript migration
This commit is contained in:
83
src/components/common/BasicScripts.astro
Normal file
83
src/components/common/BasicScripts.astro
Normal file
@ -0,0 +1,83 @@
|
||||
---
|
||||
---
|
||||
|
||||
<script is:inline>
|
||||
// Set "light" theme as default
|
||||
// if (!localStorage.theme) {
|
||||
// localStorage.theme = "light";
|
||||
// }
|
||||
|
||||
if (
|
||||
localStorage.theme === 'dark' ||
|
||||
(!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)
|
||||
) {
|
||||
document.documentElement.classList.add('dark');
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark');
|
||||
}
|
||||
|
||||
function attachEvent(selector, event, fn) {
|
||||
const matches = document.querySelectorAll(selector);
|
||||
if (matches && matches.length) {
|
||||
matches.forEach((elem) => {
|
||||
elem.addEventListener(event, () => fn(elem), false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
window.onload = function () {
|
||||
attachEvent('[data-aw-toggle-menu]', 'click', function (elem) {
|
||||
elem.classList.toggle('expanded');
|
||||
document.body.classList.toggle('overflow-hidden');
|
||||
document.getElementById('header')?.classList.toggle('h-screen');
|
||||
document.querySelector('#header nav')?.classList.toggle('hidden');
|
||||
});
|
||||
|
||||
attachEvent('[data-aw-toggle-color-scheme]', 'click', function () {
|
||||
document.documentElement.classList.toggle('dark');
|
||||
localStorage.theme = document.documentElement.classList.contains('dark') ? 'dark' : 'light';
|
||||
});
|
||||
|
||||
attachEvent('[data-aw-social-share]', 'click', function (elem) {
|
||||
const network = elem.getAttribute('data-aw-social-share');
|
||||
const url = encodeURIComponent(elem.getAttribute('data-aw-url'));
|
||||
const text = encodeURIComponent(elem.getAttribute('data-aw-text'));
|
||||
|
||||
let href;
|
||||
switch (network) {
|
||||
case 'facebook':
|
||||
href = `https://www.facebook.com/sharer.php?u=${url}`;
|
||||
break;
|
||||
case 'twitter':
|
||||
href = `https://twitter.com/intent/tweet?url=${url}&text=${text}`;
|
||||
break;
|
||||
case 'linkedin':
|
||||
href = `https://www.linkedin.com/shareArticle?mini=true&url=${url}&title=${text}`;
|
||||
break;
|
||||
case 'whatsapp':
|
||||
href = `https://wa.me/?text=${text}%20${url}`;
|
||||
break;
|
||||
case 'mail':
|
||||
href = `mailto:?subject=%22${text}%22&body=${text}%20${url}`;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
const newlink = document.createElement('a');
|
||||
newlink.target = '_blank';
|
||||
newlink.href = href;
|
||||
newlink.click();
|
||||
});
|
||||
};
|
||||
window.onpageshow = function () {
|
||||
const elem = document.querySelector('[data-aw-toggle-menu]');
|
||||
if (elem) {
|
||||
elem.classList.remove('expanded');
|
||||
}
|
||||
document.body.classList.remove('overflow-hidden');
|
||||
document.getElementById('header')?.classList.remove('h-screen');
|
||||
document.querySelector('#header nav')?.classList.add('hidden');
|
||||
};
|
||||
</script>
|
7
src/components/common/ExtraMetaTags.astro
Normal file
7
src/components/common/ExtraMetaTags.astro
Normal file
@ -0,0 +1,7 @@
|
||||
---
|
||||
import { getRelativeLink } from '~/utils/permalinks';
|
||||
---
|
||||
|
||||
<link rel="shortcut icon" href={getRelativeLink('/favicon.ico')} />
|
||||
<link rel="icon" type="image/svg+xml" href={getRelativeLink('/favicon.svg')} />
|
||||
<link rel="mask-icon" href={getRelativeLink('/favicon.svg')} color="#8D46E7" />
|
5
src/components/common/Fonts.astro
Normal file
5
src/components/common/Fonts.astro
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
import '@fontsource/inter/variable.css';
|
||||
---
|
||||
|
||||
<!-- Or Google Fonts -->
|
6
src/components/common/Logo.astro
Normal file
6
src/components/common/Logo.astro
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
---
|
||||
|
||||
<span class="self-center ml-2 text-2xl md:text-xl font-bold text-gray-900 whitespace-nowrap dark:text-white">
|
||||
🚀 AstroWind</span
|
||||
>
|
90
src/components/common/MetaTags.astro
Normal file
90
src/components/common/MetaTags.astro
Normal file
@ -0,0 +1,90 @@
|
||||
---
|
||||
import { AstroSeo } from '@astrolib/seo';
|
||||
import { GoogleAnalytics } from '@astrolib/analytics';
|
||||
import { getImage } from '@astrojs/image';
|
||||
import { getRelativeUrlByFilePath } from '~/utils/directories';
|
||||
|
||||
import { SITE } from '~/config.mjs';
|
||||
import Fonts from '~/components/common/Fonts.astro';
|
||||
import ExtraMetaTags from '~/components/common/ExtraMetaTags.astro';
|
||||
import SplitbeeAnalytics from './SplitbeeAnalytics.astro';
|
||||
|
||||
import { MetaSEO } from '~/types';
|
||||
|
||||
const defaultImage = SITE.defaultImage
|
||||
? (
|
||||
await getImage({
|
||||
src: SITE.defaultImage,
|
||||
alt: 'Default image',
|
||||
width: 1200,
|
||||
height: 628,
|
||||
})
|
||||
).src
|
||||
: '';
|
||||
|
||||
export interface Props extends MetaSEO {}
|
||||
|
||||
const {
|
||||
title = SITE.name,
|
||||
description = '',
|
||||
image: _image = defaultImage,
|
||||
|
||||
canonical,
|
||||
noindex = false,
|
||||
nofollow = false,
|
||||
|
||||
ogTitle = title,
|
||||
ogType = 'website',
|
||||
} = Astro.props;
|
||||
|
||||
const image =
|
||||
typeof _image === 'string'
|
||||
? new URL(_image, Astro.site)
|
||||
: _image && typeof _image['src'] !== 'undefined'
|
||||
? // @ts-ignore
|
||||
new URL(getRelativeUrlByFilePath(_image.src), Astro.site)
|
||||
: null;
|
||||
---
|
||||
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
|
||||
<AstroSeo
|
||||
title={title}
|
||||
description={description}
|
||||
canonical={String(canonical)}
|
||||
noindex={noindex}
|
||||
nofollow={nofollow}
|
||||
openGraph={{
|
||||
url: String(canonical),
|
||||
title: ogTitle,
|
||||
description: description,
|
||||
type: ogType,
|
||||
images: image
|
||||
? [
|
||||
{
|
||||
url: image.toString(),
|
||||
alt: ogTitle,
|
||||
},
|
||||
]
|
||||
: undefined,
|
||||
// site_name: 'SiteName',
|
||||
}}
|
||||
twitter={{
|
||||
// handle: '@handle',
|
||||
// site: '@site',
|
||||
cardType: image ? 'summary_large_image' : undefined,
|
||||
}}
|
||||
/>
|
||||
|
||||
<Fonts />
|
||||
|
||||
<!-- Google Site Verification -->
|
||||
{SITE.googleSiteVerificationId && <meta name="google-site-verification" content={SITE.googleSiteVerificationId} />}
|
||||
|
||||
<!-- Google Analytics -->
|
||||
{SITE.googleAnalyticsId && <GoogleAnalytics id={String(SITE.googleAnalyticsId)} partytown={true} />}
|
||||
|
||||
{SITE.splitbeeAnalytics?.enabled && <SplitbeeAnalytics {...SITE.splitbeeAnalytics} />}
|
||||
|
||||
<ExtraMetaTags />
|
34
src/components/common/Pagination.astro
Normal file
34
src/components/common/Pagination.astro
Normal file
@ -0,0 +1,34 @@
|
||||
---
|
||||
import { Icon } from 'astro-icon';
|
||||
import { getRelativeLink } from '~/utils/permalinks';
|
||||
|
||||
export interface Props {
|
||||
prevUrl: string;
|
||||
nextUrl: string;
|
||||
prevText?: string;
|
||||
nextText?: string;
|
||||
}
|
||||
|
||||
const { prevUrl, nextUrl, prevText = 'Newer posts', nextText = 'Older posts' } = Astro.props;
|
||||
---
|
||||
|
||||
{
|
||||
(prevUrl || nextUrl) && (
|
||||
<div class="container flex">
|
||||
<div class="flex flex-row mx-auto container justify-between">
|
||||
<a href={getRelativeLink(prevUrl)} class={`btn btn-ghost px-3 mr-2 ${!prevUrl ? 'invisible' : ''}`}>
|
||||
<div class="flex flex-row align-middle">
|
||||
<Icon name="tabler:chevron-left" class="w-6 h-6" />
|
||||
<p class="ml-2">{prevText}</p>
|
||||
</div>
|
||||
</a>
|
||||
<a href={getRelativeLink(nextUrl)} class={`btn btn-ghost px-3 ${!nextUrl ? 'invisible' : ''}`}>
|
||||
<div class="flex flex-row align-middle">
|
||||
<span class="mr-2">{nextText}</span>
|
||||
<Icon name="tabler:chevron-right" class="w-6 h-6" />
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
30
src/components/common/SocialShare.astro
Normal file
30
src/components/common/SocialShare.astro
Normal file
@ -0,0 +1,30 @@
|
||||
---
|
||||
import { Icon } from 'astro-icon';
|
||||
|
||||
export interface Props {
|
||||
text: string;
|
||||
url: string | URL;
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const { text, url, class: className = 'inline-block' } = Astro.props;
|
||||
---
|
||||
|
||||
<div class={className}>
|
||||
<span class="align-super font-bold">Share:</span>
|
||||
<button class="ml-2" title="Twitter Share" data-aw-social-share="twitter" data-aw-url={url} data-aw-text={text}
|
||||
><Icon name="logos:twitter" class="w-6 h-6" />
|
||||
</button>
|
||||
<button class="ml-2" title="Facebook Share" data-aw-social-share="facebook" data-aw-url={url}
|
||||
><Icon name="logos:facebook" class="w-6 h-6" />
|
||||
</button>
|
||||
<button class="ml-2" title="Linkedin Share" data-aw-social-share="linkedin" data-aw-url={url} data-aw-text={text}
|
||||
><Icon name="logos:linkedin-icon" class="w-6 h-6" />
|
||||
</button>
|
||||
<button class="ml-2" title="Whatsapp Share" data-aw-social-share="whatsapp" data-aw-url={url} data-aw-text={text}
|
||||
><Icon name="logos:whatsapp" class="w-6 h-6" />
|
||||
</button>
|
||||
<button class="ml-2" title="Email Share" data-aw-social-share="mail" data-aw-url={url} data-aw-text={text}
|
||||
><Icon name="tabler:mail" class="w-6 h-6" />
|
||||
</button>
|
||||
</div>
|
6
src/components/common/SplitbeeAnalytics.astro
Normal file
6
src/components/common/SplitbeeAnalytics.astro
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
const { doNotTrack = true, noCookieMode = false, url = 'https://cdn.splitbee.io/sb.js' } = Astro.props;
|
||||
---
|
||||
|
||||
<!-- Splitbee Analytics -->
|
||||
<script data-respect-dnt={doNotTrack} data-no-cookie={noCookieMode} async src={url}></script>
|
24
src/components/common/Tags.astro
Normal file
24
src/components/common/Tags.astro
Normal file
@ -0,0 +1,24 @@
|
||||
---
|
||||
import { getPermalink } from '~/utils/permalinks';
|
||||
|
||||
import type { Post } from '~/types';
|
||||
|
||||
export interface Props {
|
||||
tags: Post['tags'];
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const { tags, class: className = 'text-sm' } = Astro.props;
|
||||
---
|
||||
|
||||
{
|
||||
tags && Array.isArray(tags) && (
|
||||
<ul class={className}>
|
||||
{tags.map((tag) => (
|
||||
<li class="bg-gray-100 dark:bg-slate-700 inline-block mr-2 mb-2 py-0.5 px-2 lowercase">
|
||||
<a href={getPermalink(tag, 'tag')}>{tag}</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)
|
||||
}
|
22
src/components/common/ToggleMenu.astro
Normal file
22
src/components/common/ToggleMenu.astro
Normal file
@ -0,0 +1,22 @@
|
||||
---
|
||||
import { Icon } from 'astro-icon';
|
||||
|
||||
export interface Props {
|
||||
label?: string;
|
||||
class?: string;
|
||||
iconClass?: string;
|
||||
iconName?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
label = 'Toggle Menu',
|
||||
class:
|
||||
className = 'ml-1.5 text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 focus:outline-none focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-700 rounded-lg text-sm p-2.5 inline-flex items-center transition',
|
||||
iconClass = 'w-6 h-6',
|
||||
iconName = 'tabler:menu',
|
||||
} = Astro.props;
|
||||
---
|
||||
|
||||
<button type="button" class={className} aria-label={label} data-aw-toggle-menu>
|
||||
<Icon name={iconName} class={iconClass} optimize={false} />
|
||||
</button>
|
22
src/components/common/ToggleTheme.astro
Normal file
22
src/components/common/ToggleTheme.astro
Normal file
@ -0,0 +1,22 @@
|
||||
---
|
||||
import { Icon } from 'astro-icon';
|
||||
|
||||
export interface Props {
|
||||
label?: string;
|
||||
class?: string;
|
||||
iconClass?: string;
|
||||
iconName?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
label = 'Toggle between Dark and Light mode',
|
||||
class:
|
||||
className = 'text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-700 rounded-lg text-sm p-2.5 inline-flex items-center',
|
||||
iconClass = 'w-6 h-6',
|
||||
iconName = 'tabler:sun',
|
||||
} = Astro.props;
|
||||
---
|
||||
|
||||
<button type="button" class={className} aria-label={label} data-aw-toggle-color-scheme>
|
||||
<Icon name={iconName} class={iconClass} />
|
||||
</button>
|
Reference in New Issue
Block a user