@aureuma/svelta 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/.changeset/README.md +8 -0
- package/.changeset/config.json +14 -0
- package/.changeset/publish-blogkit.md +5 -0
- package/.github/workflows/release.yml +65 -0
- package/LICENSE +22 -0
- package/README.md +35 -0
- package/docs/mintlify-blog-study.md +697 -0
- package/package.json +59 -0
- package/packages/blogkit/CHANGELOG.md +6 -0
- package/packages/blogkit/LICENSE +22 -0
- package/packages/blogkit/README.md +93 -0
- package/packages/blogkit/dist/components/blog/Avatar.svelte +15 -0
- package/packages/blogkit/dist/components/blog/Avatar.svelte.d.ts +22 -0
- package/packages/blogkit/dist/components/blog/BackLink.svelte +23 -0
- package/packages/blogkit/dist/components/blog/BackLink.svelte.d.ts +21 -0
- package/packages/blogkit/dist/components/blog/BlogCard.svelte +37 -0
- package/packages/blogkit/dist/components/blog/BlogCard.svelte.d.ts +22 -0
- package/packages/blogkit/dist/components/blog/BlogHeroCard.svelte +36 -0
- package/packages/blogkit/dist/components/blog/BlogHeroCard.svelte.d.ts +21 -0
- package/packages/blogkit/dist/components/blog/Container.svelte +8 -0
- package/packages/blogkit/dist/components/blog/Container.svelte.d.ts +29 -0
- package/packages/blogkit/dist/components/blog/ImageLightbox.svelte +58 -0
- package/packages/blogkit/dist/components/blog/ImageLightbox.svelte.d.ts +24 -0
- package/packages/blogkit/dist/components/blog/MorePosts.svelte +15 -0
- package/packages/blogkit/dist/components/blog/MorePosts.svelte.d.ts +21 -0
- package/packages/blogkit/dist/components/blog/ShareButtons.svelte +113 -0
- package/packages/blogkit/dist/components/blog/ShareButtons.svelte.d.ts +23 -0
- package/packages/blogkit/dist/components/blog/SummaryCard.svelte +11 -0
- package/packages/blogkit/dist/components/blog/SummaryCard.svelte.d.ts +20 -0
- package/packages/blogkit/dist/components/blog/TagTabs.svelte +32 -0
- package/packages/blogkit/dist/components/blog/TagTabs.svelte.d.ts +23 -0
- package/packages/blogkit/dist/index.d.ts +11 -0
- package/packages/blogkit/dist/index.js +11 -0
- package/packages/blogkit/dist/server/blog.d.ts +39 -0
- package/packages/blogkit/dist/server/blog.js +222 -0
- package/packages/blogkit/dist/server/index.d.ts +1 -0
- package/packages/blogkit/dist/server/index.js +1 -0
- package/packages/blogkit/dist/theme/ThemeSwitcher.svelte +34 -0
- package/packages/blogkit/dist/theme/ThemeSwitcher.svelte.d.ts +21 -0
- package/packages/blogkit/dist/theme/index.d.ts +2 -0
- package/packages/blogkit/dist/theme/index.js +2 -0
- package/packages/blogkit/dist/theme/store.d.ts +12 -0
- package/packages/blogkit/dist/theme/store.js +50 -0
- package/packages/blogkit/dist/types/blog.d.ts +31 -0
- package/packages/blogkit/dist/types/blog.js +1 -0
- package/packages/blogkit/package.json +66 -0
- package/packages/blogkit/src/lib/components/blog/Avatar.svelte +15 -0
- package/packages/blogkit/src/lib/components/blog/BackLink.svelte +23 -0
- package/packages/blogkit/src/lib/components/blog/BlogCard.svelte +37 -0
- package/packages/blogkit/src/lib/components/blog/BlogHeroCard.svelte +36 -0
- package/packages/blogkit/src/lib/components/blog/Container.svelte +8 -0
- package/packages/blogkit/src/lib/components/blog/ImageLightbox.svelte +58 -0
- package/packages/blogkit/src/lib/components/blog/MorePosts.svelte +15 -0
- package/packages/blogkit/src/lib/components/blog/ShareButtons.svelte +113 -0
- package/packages/blogkit/src/lib/components/blog/SummaryCard.svelte +11 -0
- package/packages/blogkit/src/lib/components/blog/TagTabs.svelte +32 -0
- package/packages/blogkit/src/lib/index.ts +15 -0
- package/packages/blogkit/src/lib/server/blog.ts +264 -0
- package/packages/blogkit/src/lib/server/index.ts +2 -0
- package/packages/blogkit/src/lib/theme/ThemeSwitcher.svelte +34 -0
- package/packages/blogkit/src/lib/theme/index.ts +3 -0
- package/packages/blogkit/src/lib/theme/store.ts +64 -0
- package/packages/blogkit/src/lib/types/blog.ts +36 -0
- package/packages/blogkit/svelte.config.js +8 -0
- package/packages/blogkit/tsconfig.json +5 -0
- package/playwright.config.ts +24 -0
- package/postcss.config.cjs +6 -0
- package/src/app.css +146 -0
- package/src/app.d.ts +13 -0
- package/src/app.html +26 -0
- package/src/content/blog/ai-summary-cards-with-frontmatter.md +32 -0
- package/src/content/blog/announcing-svelta-blog.md +19 -0
- package/src/content/blog/best-practices-ship-with-checklists.md +26 -0
- package/src/content/blog/building-a-mintlify-inspired-blog.md +49 -0
- package/src/content/blog/design-tokens-that-scale.md +47 -0
- package/src/content/blog/for-founders-why-speed-matters.md +23 -0
- package/src/content/blog/infinite-scroll-with-intersection-observer.md +37 -0
- package/src/content/blog/markdown-kitchen-sink.md +101 -0
- package/src/content/blog/markdown-pipeline-mdsvex-shiki.md +39 -0
- package/src/content/blog/rss-feeds-that-actually-work.md +25 -0
- package/src/content/blog/tag-tabs-and-mobile-fade-masks.md +25 -0
- package/src/lib/assets/favicon.svg +1 -0
- package/src/lib/components/site/SiteFooter.svelte +24 -0
- package/src/lib/components/site/SiteHeader.svelte +36 -0
- package/src/lib/content/authors.ts +28 -0
- package/src/lib/index.ts +1 -0
- package/src/lib/server/blog.ts +22 -0
- package/src/lib/server/rss.ts +58 -0
- package/src/lib/server/seo.ts +31 -0
- package/src/lib/stores/theme.ts +10 -0
- package/src/lib/types/blog.ts +1 -0
- package/src/routes/+layout.svelte +31 -0
- package/src/routes/+page.svelte +44 -0
- package/src/routes/blog/+page.server.ts +28 -0
- package/src/routes/blog/+page.svelte +122 -0
- package/src/routes/blog/[slug]/+page.server.ts +39 -0
- package/src/routes/blog/[slug]/+page.svelte +118 -0
- package/src/routes/blog/posts.json/+server.ts +32 -0
- package/src/routes/feed.xml/+server.ts +21 -0
- package/static/blog/authors/alex.svg +13 -0
- package/static/blog/authors/maria.svg +13 -0
- package/static/blog/authors/shawn.svg +13 -0
- package/static/blog/covers/ai-summary.svg +38 -0
- package/static/blog/covers/design-tokens.svg +37 -0
- package/static/blog/covers/infinite-scroll.svg +38 -0
- package/static/blog/covers/kitchen-sink.svg +36 -0
- package/static/blog/covers/markdown-pipeline.svg +41 -0
- package/static/blog/covers/mintlify-style.svg +35 -0
- package/static/blog/covers/rss.svg +34 -0
- package/static/robots.txt +3 -0
- package/svelte.config.js +70 -0
- package/tailwind.config.cjs +133 -0
- package/tests/blog.spec.ts +63 -0
- package/tsconfig.json +21 -0
- package/vite.config.ts +14 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/** @type {import('tailwindcss').Config} */
|
|
2
|
+
module.exports = {
|
|
3
|
+
darkMode: 'class',
|
|
4
|
+
content: [
|
|
5
|
+
'./src/**/*.{html,js,svelte,ts,md}',
|
|
6
|
+
'./src/content/**/*.{md}',
|
|
7
|
+
'./packages/blogkit/src/**/*.{svelte,ts}',
|
|
8
|
+
'./packages/blogkit/dist/**/*.{js,ts,svelte}'
|
|
9
|
+
],
|
|
10
|
+
theme: {
|
|
11
|
+
extend: {
|
|
12
|
+
colors: {
|
|
13
|
+
background: {
|
|
14
|
+
main: 'rgb(var(--c-background-main) / <alpha-value>)',
|
|
15
|
+
soft: 'rgb(var(--c-background-soft) / <alpha-value>)',
|
|
16
|
+
invert: 'rgb(var(--c-background-invert) / <alpha-value>)'
|
|
17
|
+
},
|
|
18
|
+
text: {
|
|
19
|
+
main: 'rgb(var(--c-text-main) / <alpha-value>)',
|
|
20
|
+
sub: 'rgb(var(--c-text-sub) / <alpha-value>)',
|
|
21
|
+
muted: 'rgb(var(--c-text-muted) / <alpha-value>)',
|
|
22
|
+
invert: 'rgb(var(--c-text-invert) / <alpha-value>)'
|
|
23
|
+
},
|
|
24
|
+
border: {
|
|
25
|
+
soft: 'rgb(var(--c-border-soft) / <alpha-value>)'
|
|
26
|
+
},
|
|
27
|
+
brand: {
|
|
28
|
+
DEFAULT: 'rgb(var(--c-brand) / <alpha-value>)',
|
|
29
|
+
soft: 'rgb(var(--c-brand-soft) / <alpha-value>)'
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
fontFamily: {
|
|
33
|
+
sans: [
|
|
34
|
+
'Inter',
|
|
35
|
+
'ui-sans-serif',
|
|
36
|
+
'system-ui',
|
|
37
|
+
'-apple-system',
|
|
38
|
+
'Segoe UI',
|
|
39
|
+
'Roboto',
|
|
40
|
+
'Helvetica',
|
|
41
|
+
'Arial',
|
|
42
|
+
'Apple Color Emoji',
|
|
43
|
+
'Segoe UI Emoji'
|
|
44
|
+
],
|
|
45
|
+
mono: [
|
|
46
|
+
'Geist Mono',
|
|
47
|
+
'ui-monospace',
|
|
48
|
+
'SFMono-Regular',
|
|
49
|
+
'Menlo',
|
|
50
|
+
'Monaco',
|
|
51
|
+
'Consolas',
|
|
52
|
+
'Liberation Mono',
|
|
53
|
+
'Courier New',
|
|
54
|
+
'monospace'
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
boxShadow: {
|
|
58
|
+
'drop-md': '0 18px 60px rgba(15, 23, 42, 0.16)'
|
|
59
|
+
},
|
|
60
|
+
typography: () => ({
|
|
61
|
+
DEFAULT: {
|
|
62
|
+
css: {
|
|
63
|
+
'--tw-prose-body': 'rgb(var(--c-text-main))',
|
|
64
|
+
'--tw-prose-headings': 'rgb(var(--c-text-main))',
|
|
65
|
+
'--tw-prose-lead': 'rgb(var(--c-text-sub))',
|
|
66
|
+
'--tw-prose-links': 'rgb(var(--c-text-main))',
|
|
67
|
+
'--tw-prose-bold': 'rgb(var(--c-text-main))',
|
|
68
|
+
'--tw-prose-counters': 'rgb(var(--c-text-muted))',
|
|
69
|
+
'--tw-prose-bullets': 'rgb(var(--c-border-soft) / 0.35)',
|
|
70
|
+
'--tw-prose-hr': 'rgb(var(--c-border-soft) / 0.12)',
|
|
71
|
+
'--tw-prose-quotes': 'rgb(var(--c-text-main))',
|
|
72
|
+
'--tw-prose-quote-borders': 'rgb(var(--c-border-soft) / 0.2)',
|
|
73
|
+
'--tw-prose-captions': 'rgb(var(--c-text-muted))',
|
|
74
|
+
'--tw-prose-code': 'rgb(var(--c-text-main))',
|
|
75
|
+
'--tw-prose-pre-code': 'rgb(var(--c-text-main))',
|
|
76
|
+
'--tw-prose-pre-bg': 'transparent',
|
|
77
|
+
'--tw-prose-th-borders': 'rgb(var(--c-border-soft) / 0.12)',
|
|
78
|
+
'--tw-prose-td-borders': 'rgb(var(--c-border-soft) / 0.12)',
|
|
79
|
+
maxWidth: 'none',
|
|
80
|
+
fontSize: '16px',
|
|
81
|
+
lineHeight: '24px',
|
|
82
|
+
letterSpacing: '-0.01em',
|
|
83
|
+
a: {
|
|
84
|
+
textDecoration: 'underline',
|
|
85
|
+
textDecorationColor: 'rgb(var(--c-border-soft) / 0.35)',
|
|
86
|
+
textUnderlineOffset: '3px'
|
|
87
|
+
},
|
|
88
|
+
'a:hover': {
|
|
89
|
+
textDecorationColor: 'rgb(var(--c-brand) / 0.85)'
|
|
90
|
+
},
|
|
91
|
+
h2: {
|
|
92
|
+
fontWeight: '500',
|
|
93
|
+
fontSize: '24px',
|
|
94
|
+
lineHeight: '31.2px',
|
|
95
|
+
letterSpacing: '-0.24px',
|
|
96
|
+
scrollMarginTop: '96px'
|
|
97
|
+
},
|
|
98
|
+
h3: {
|
|
99
|
+
fontWeight: '500',
|
|
100
|
+
fontSize: '20px',
|
|
101
|
+
lineHeight: '26px',
|
|
102
|
+
letterSpacing: '-0.24px',
|
|
103
|
+
scrollMarginTop: '96px'
|
|
104
|
+
},
|
|
105
|
+
code: {
|
|
106
|
+
fontWeight: '500',
|
|
107
|
+
backgroundColor: 'rgb(var(--c-background-soft))',
|
|
108
|
+
padding: '0.2em 0.35em',
|
|
109
|
+
borderRadius: '6px'
|
|
110
|
+
},
|
|
111
|
+
'code::before': { content: '""' },
|
|
112
|
+
'code::after': { content: '""' },
|
|
113
|
+
pre: {
|
|
114
|
+
background: 'transparent',
|
|
115
|
+
padding: '0',
|
|
116
|
+
margin: '0'
|
|
117
|
+
},
|
|
118
|
+
blockquote: {
|
|
119
|
+
borderLeftColor: 'rgb(var(--c-border-soft) / 0.35)'
|
|
120
|
+
},
|
|
121
|
+
'blockquote p:first-of-type::before': { content: '""' },
|
|
122
|
+
'blockquote p:last-of-type::after': { content: '""' },
|
|
123
|
+
img: {
|
|
124
|
+
borderRadius: '10px',
|
|
125
|
+
border: '1px solid rgb(var(--c-border-soft) / 0.07)'
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
})
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
plugins: [require('@tailwindcss/typography')]
|
|
133
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
test('blog index renders hero, tags, and paginates', async ({ page }) => {
|
|
4
|
+
await page.goto('/blog');
|
|
5
|
+
|
|
6
|
+
await expect(page.getByTestId('blog-hero')).toBeVisible();
|
|
7
|
+
await expect(page.getByTestId('blog-tags')).toBeVisible();
|
|
8
|
+
|
|
9
|
+
const cards = page.getByTestId('blog-card');
|
|
10
|
+
await expect(cards).toHaveCount(8);
|
|
11
|
+
|
|
12
|
+
// Trigger infinite scroll: scroll near bottom and wait for additional cards.
|
|
13
|
+
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
|
|
14
|
+
await expect.poll(async () => cards.count()).toBeGreaterThan(8);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('post page renders summary, shiki blocks, and more posts', async ({ page }) => {
|
|
18
|
+
await page.goto('/blog/ai-summary-cards-with-frontmatter');
|
|
19
|
+
|
|
20
|
+
await expect(page.getByRole('heading', { level: 1 })).toBeVisible();
|
|
21
|
+
await expect(page.getByTestId('blog-summary')).toBeVisible();
|
|
22
|
+
await expect.poll(async () => page.locator('pre.shiki').count()).toBeGreaterThan(0);
|
|
23
|
+
|
|
24
|
+
// Heading anchors from rehype-autolink-headings should exist.
|
|
25
|
+
await expect
|
|
26
|
+
.poll(async () => page.locator('.blog-prose .heading-anchor').count())
|
|
27
|
+
.toBeGreaterThan(0);
|
|
28
|
+
|
|
29
|
+
await expect(page.getByTestId('blog-more-posts')).toBeVisible();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('theme toggling applies the expected html class', async ({ page }) => {
|
|
33
|
+
await page.goto('/');
|
|
34
|
+
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
|
|
35
|
+
const darkBtn = page.getByRole('button', { name: 'Dark' });
|
|
36
|
+
await darkBtn.click();
|
|
37
|
+
|
|
38
|
+
// If hydration/event binding is broken, this will never flip.
|
|
39
|
+
await expect(darkBtn).toHaveAttribute('aria-pressed', 'true');
|
|
40
|
+
await expect(page.locator('html')).toHaveClass(/dark/);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('rss feed is valid xml-ish and links do not include .md', async ({ request }) => {
|
|
44
|
+
const res = await request.get('/feed.xml');
|
|
45
|
+
expect(res.ok()).toBeTruthy();
|
|
46
|
+
|
|
47
|
+
const ct = res.headers()['content-type'] ?? '';
|
|
48
|
+
expect(ct).toContain('application/rss+xml');
|
|
49
|
+
|
|
50
|
+
const body = await res.text();
|
|
51
|
+
expect(body).toContain('<rss');
|
|
52
|
+
expect(body).toContain('<channel>');
|
|
53
|
+
expect(body).toContain('/blog/ai-summary-cards-with-frontmatter');
|
|
54
|
+
expect(body).not.toContain('.md</link>');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test('mobile layout folds share UI into the content column', async ({ page }) => {
|
|
58
|
+
await page.setViewportSize({ width: 390, height: 844 });
|
|
59
|
+
await page.goto('/blog/ai-summary-cards-with-frontmatter');
|
|
60
|
+
|
|
61
|
+
await expect(page.getByTestId('blog-share-mobile')).toBeVisible();
|
|
62
|
+
await expect(page.getByTestId('blog-share-desktop')).toBeHidden();
|
|
63
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./.svelte-kit/tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"rewriteRelativeImportExtensions": true,
|
|
5
|
+
"allowJs": true,
|
|
6
|
+
"checkJs": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"forceConsistentCasingInFileNames": true,
|
|
9
|
+
"resolveJsonModule": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"sourceMap": true,
|
|
12
|
+
"strict": true,
|
|
13
|
+
"moduleResolution": "bundler"
|
|
14
|
+
},
|
|
15
|
+
"exclude": ["packages/**/dist/**"]
|
|
16
|
+
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
|
|
17
|
+
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
|
|
18
|
+
//
|
|
19
|
+
// To make changes to top-level options such as include and exclude, we recommend extending
|
|
20
|
+
// the generated config; see https://svelte.dev/docs/kit/configuration#typescript
|
|
21
|
+
}
|
package/vite.config.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { sveltekit } from '@sveltejs/kit/vite';
|
|
2
|
+
import { defineConfig } from 'vite';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
plugins: [sveltekit()],
|
|
7
|
+
server: {
|
|
8
|
+
fs: {
|
|
9
|
+
// Allow local workspace packages to be served in dev.
|
|
10
|
+
strict: false,
|
|
11
|
+
allow: [path.resolve('./packages'), path.resolve('./src'), path.resolve('./node_modules')]
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
});
|