809f89af08
- Content collection (one folder per post) with zod schema - /blog, category and tag archives with /sayfa/<n>/ pagination - Post page: breadcrumbs, date badges, share bar, TOC, DIY notice, code copy, license line, prev/next, BlogPosting + BreadcrumbList JSON-LD - Sidebar: Pagefind search, categories, featured fallback, tag cloud - Sätteri HAST plugins for figure/figcaption and external links - Dual-theme Shiki, themed prose, RSS feed, latest posts on home - Three sample posts marked as examples Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
83 lines
2.7 KiB
Plaintext
83 lines
2.7 KiB
Plaintext
---
|
|
import { Icon } from 'astro-icon/components';
|
|
import { blog, site } from '../../lib/data';
|
|
|
|
export interface Props {
|
|
url: string;
|
|
title: string;
|
|
}
|
|
|
|
const { url, title } = Astro.props;
|
|
const fill = (tpl: string) =>
|
|
tpl.replace('{url}', encodeURIComponent(url)).replace('{title}', encodeURIComponent(title));
|
|
const btn =
|
|
'border-line hover:border-fg hover:bg-fg hover:text-bg inline-flex size-11 cursor-pointer items-center justify-center border transition-colors';
|
|
---
|
|
|
|
<div data-share data-url={url} data-title={title} data-copied={blog.post.copied}>
|
|
<p class="font-display mb-3 text-sm font-bold tracking-wide uppercase" id="share-label">
|
|
{blog.post.shareLabel}
|
|
</p>
|
|
<ul class="flex flex-wrap gap-2" aria-labelledby="share-label">
|
|
{blog.share.map((s) => (
|
|
<li>
|
|
<a
|
|
href={fill(s.url)}
|
|
target={s.id === 'email' ? undefined : '_blank'}
|
|
rel={s.id === 'email' ? undefined : 'noopener noreferrer'}
|
|
title={s.label}
|
|
class={btn}
|
|
>
|
|
<Icon name={s.icon} class="size-5" aria-hidden="true" />
|
|
<span class="sr-only">
|
|
{s.label}
|
|
{s.id !== 'email' && ` ${site.ui.newTab}`}
|
|
</span>
|
|
</a>
|
|
</li>
|
|
))}
|
|
<li>
|
|
<button type="button" data-share-copy title={blog.post.copyLink} class={btn}>
|
|
<Icon name="tabler:link" class="size-5" aria-hidden="true" />
|
|
<span class="sr-only">{blog.post.copyLink}</span>
|
|
</button>
|
|
</li>
|
|
<li hidden data-share-native-item>
|
|
<button type="button" data-share-native title={blog.post.nativeShare} class={btn}>
|
|
<Icon name="tabler:share" class="size-5" aria-hidden="true" />
|
|
<span class="sr-only">{blog.post.nativeShare}</span>
|
|
</button>
|
|
</li>
|
|
</ul>
|
|
<p
|
|
data-share-status
|
|
role="status"
|
|
aria-live="polite"
|
|
class="text-accent-text mt-2 min-h-5 text-sm font-semibold"
|
|
></p>
|
|
</div>
|
|
|
|
<script>
|
|
for (const root of document.querySelectorAll<HTMLElement>('[data-share]')) {
|
|
const { url = location.href, title = document.title, copied = '' } = root.dataset;
|
|
const status = root.querySelector<HTMLElement>('[data-share-status]')!;
|
|
|
|
root.querySelector('[data-share-copy]')?.addEventListener('click', async () => {
|
|
try {
|
|
await navigator.clipboard.writeText(url);
|
|
status.textContent = copied;
|
|
setTimeout(() => (status.textContent = ''), 2500);
|
|
} catch {
|
|
prompt('', url);
|
|
}
|
|
});
|
|
|
|
if (typeof navigator.share === 'function') {
|
|
root.querySelector<HTMLElement>('[data-share-native-item]')!.hidden = false;
|
|
root.querySelector('[data-share-native]')!.addEventListener('click', () => {
|
|
navigator.share({ url, title }).catch(() => {});
|
|
});
|
|
}
|
|
}
|
|
</script>
|