ecopages 0.2.0-alpha.31 → 0.2.0-alpha.33
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/package.json +2 -2
- package/templates/blog-jsx/.env.example +4 -0
- package/templates/blog-jsx/app.ts +6 -0
- package/templates/blog-jsx/eco.config.ts +45 -0
- package/templates/blog-jsx/modules.d.ts +4 -0
- package/templates/blog-jsx/package.json +27 -0
- package/templates/blog-jsx/src/components/icons.kita.tsx +46 -0
- package/templates/blog-jsx/src/components/theme-toggle.css +33 -0
- package/templates/blog-jsx/src/components/theme-toggle.kita.tsx +22 -0
- package/templates/blog-jsx/src/components/theme-toggle.script.ts +39 -0
- package/templates/blog-jsx/src/images/ezi-76GU53nkLSU-unsplash.jpg +0 -0
- package/templates/blog-jsx/src/images/theodore-poncet-QZePhoGqD7w-unsplash.jpg +0 -0
- package/templates/blog-jsx/src/images/urban-vintage-78A265wPiO4-unsplash.jpg +0 -0
- package/templates/blog-jsx/src/includes/head.kita.tsx +20 -0
- package/templates/blog-jsx/src/includes/html.kita.tsx +31 -0
- package/templates/blog-jsx/src/includes/seo.kita.tsx +28 -0
- package/templates/blog-jsx/src/layouts/base-layout/base-layout.css +27 -0
- package/templates/blog-jsx/src/layouts/base-layout/base-layout.kita.tsx +42 -0
- package/templates/blog-jsx/src/layouts/base-layout/base-layout.script.ts +5 -0
- package/templates/blog-jsx/src/pages/404.css +27 -0
- package/templates/blog-jsx/src/pages/404.kita.tsx +21 -0
- package/templates/blog-jsx/src/pages/about.kita.tsx +31 -0
- package/templates/blog-jsx/src/pages/index.css +43 -0
- package/templates/blog-jsx/src/pages/index.kita.tsx +83 -0
- package/templates/blog-jsx/src/pages/mdx-example.mdx +48 -0
- package/templates/blog-jsx/src/pages/posts/[slug].kita.tsx +101 -0
- package/templates/blog-jsx/src/pages/posts/post.css +22 -0
- package/templates/blog-jsx/src/public/assets/favicon.svg +1 -0
- package/templates/blog-jsx/src/public/assets/fonts/alegreya-sans-latin-400-normal.woff2 +0 -0
- package/templates/blog-jsx/src/public/assets/fonts/alegreya-sans-latin-500-normal.woff2 +0 -0
- package/templates/blog-jsx/src/public/assets/fonts/alegreya-sans-latin-700-normal.woff2 +0 -0
- package/templates/blog-jsx/src/public/assets/fonts/cambo-latin-400-normal.woff2 +0 -0
- package/templates/blog-jsx/src/public/assets/images/default-og.png +0 -0
- package/templates/blog-jsx/src/public/assets/images/default-og.webp +0 -0
- package/templates/blog-jsx/src/styles/tailwind.css +121 -0
- package/templates/blog-jsx/src/styles/theme.css +90 -0
- package/templates/blog-jsx/tsconfig.json +28 -0
- package/templates/blog-react/.env.example +4 -0
- package/templates/blog-react/README.md +3 -0
- package/templates/blog-react/app.ts +6 -0
- package/templates/blog-react/eco.config.ts +47 -0
- package/templates/blog-react/modules.d.ts +3 -0
- package/templates/blog-react/package.json +35 -0
- package/templates/blog-react/src/components/icons.tsx +49 -0
- package/templates/blog-react/src/components/theme-toggle.css +16 -0
- package/templates/blog-react/src/components/theme-toggle.tsx +52 -0
- package/templates/blog-react/src/images/ezi-76GU53nkLSU-unsplash.jpg +0 -0
- package/templates/blog-react/src/images/theodore-poncet-QZePhoGqD7w-unsplash.jpg +0 -0
- package/templates/blog-react/src/images/urban-vintage-78A265wPiO4-unsplash.jpg +0 -0
- package/templates/blog-react/src/includes/head.tsx +21 -0
- package/templates/blog-react/src/includes/html.tsx +27 -0
- package/templates/blog-react/src/includes/seo.tsx +28 -0
- package/templates/blog-react/src/layouts/base-layout/base-layout.css +39 -0
- package/templates/blog-react/src/layouts/base-layout/base-layout.tsx +43 -0
- package/templates/blog-react/src/layouts/base-layout/index.ts +1 -0
- package/templates/blog-react/src/pages/404.css +27 -0
- package/templates/blog-react/src/pages/404.tsx +22 -0
- package/templates/blog-react/src/pages/about.tsx +32 -0
- package/templates/blog-react/src/pages/index.css +43 -0
- package/templates/blog-react/src/pages/index.tsx +83 -0
- package/templates/blog-react/src/pages/mdx-example.mdx +49 -0
- package/templates/blog-react/src/pages/mdx-page-2.mdx +11 -0
- package/templates/blog-react/src/pages/posts/[slug].tsx +103 -0
- package/templates/blog-react/src/pages/posts/post.css +22 -0
- package/templates/blog-react/src/public/assets/favicon.svg +1 -0
- package/templates/blog-react/src/public/assets/fonts/alegreya-sans-latin-400-normal.woff2 +0 -0
- package/templates/blog-react/src/public/assets/fonts/alegreya-sans-latin-500-normal.woff2 +0 -0
- package/templates/blog-react/src/public/assets/fonts/alegreya-sans-latin-700-normal.woff2 +0 -0
- package/templates/blog-react/src/public/assets/fonts/cambo-latin-400-normal.woff2 +0 -0
- package/templates/blog-react/src/public/assets/images/default-og.png +0 -0
- package/templates/blog-react/src/public/assets/images/default-og.webp +0 -0
- package/templates/blog-react/src/styles/router.css +1 -0
- package/templates/blog-react/src/styles/tailwind.css +121 -0
- package/templates/blog-react/src/styles/theme.css +72 -0
- package/templates/blog-react/tsconfig.json +20 -0
- package/templates/starter-ghtml/.env.example +4 -0
- package/templates/starter-ghtml/README.md +48 -0
- package/templates/starter-ghtml/app.ts +6 -0
- package/templates/starter-ghtml/eco.config.ts +26 -0
- package/templates/starter-ghtml/modules.d.ts +3 -0
- package/templates/starter-ghtml/package.json +22 -0
- package/templates/starter-ghtml/src/components/radiant-counter/index.ts +1 -0
- package/templates/starter-ghtml/src/components/radiant-counter/radiant-counter.css +10 -0
- package/templates/starter-ghtml/src/components/radiant-counter/radiant-counter.script.ts +34 -0
- package/templates/starter-ghtml/src/components/radiant-counter/radiant-counter.ts +17 -0
- package/templates/starter-ghtml/src/includes/head.ghtml.ts +17 -0
- package/templates/starter-ghtml/src/includes/html.ghtml.ts +21 -0
- package/templates/starter-ghtml/src/includes/seo.ghtml.ts +25 -0
- package/templates/starter-ghtml/src/layouts/base-layout/base-layout.css +7 -0
- package/templates/starter-ghtml/src/layouts/base-layout/base-layout.script.ts +0 -0
- package/templates/starter-ghtml/src/layouts/base-layout/base-layout.ts +16 -0
- package/templates/starter-ghtml/src/layouts/base-layout/index.ts +1 -0
- package/templates/starter-ghtml/src/pages/404.css +9 -0
- package/templates/starter-ghtml/src/pages/404.ts +18 -0
- package/templates/starter-ghtml/src/pages/index.css +11 -0
- package/templates/starter-ghtml/src/pages/index.ts +38 -0
- package/templates/starter-ghtml/src/public/assets/favicon.svg +1 -0
- package/templates/starter-ghtml/src/public/assets/images/default-og.png +0 -0
- package/templates/starter-ghtml/src/public/assets/images/default-og.webp +0 -0
- package/templates/starter-ghtml/src/styles/tailwind.css +1 -0
- package/templates/starter-ghtml/tsconfig.json +20 -0
- package/templates/starter-jsx/.env.example +4 -0
- package/templates/starter-jsx/README.md +40 -0
- package/templates/starter-jsx/app.ts +6 -0
- package/templates/starter-jsx/eco.config.ts +47 -0
- package/templates/starter-jsx/modules.d.ts +4 -0
- package/templates/starter-jsx/package-lock.json +6774 -0
- package/templates/starter-jsx/package.json +26 -0
- package/templates/starter-jsx/src/components/demo-container.css +30 -0
- package/templates/starter-jsx/src/components/demo-container.kita.tsx +23 -0
- package/templates/starter-jsx/src/components/icons.kita.tsx +46 -0
- package/templates/starter-jsx/src/components/radiant-counter.css +46 -0
- package/templates/starter-jsx/src/components/radiant-counter.kita.tsx +48 -0
- package/templates/starter-jsx/src/components/radiant-counter.script.ts +34 -0
- package/templates/starter-jsx/src/components/showcase.mdx +5 -0
- package/templates/starter-jsx/src/components/theme-toggle.css +25 -0
- package/templates/starter-jsx/src/components/theme-toggle.kita.tsx +22 -0
- package/templates/starter-jsx/src/components/theme-toggle.script.ts +39 -0
- package/templates/starter-jsx/src/images/kita-kamakura.png +0 -0
- package/templates/starter-jsx/src/includes/html.kita.tsx +28 -0
- package/templates/starter-jsx/src/includes/seo.kita.tsx +24 -0
- package/templates/starter-jsx/src/layouts/base-layout/base-layout.css +20 -0
- package/templates/starter-jsx/src/layouts/base-layout/base-layout.kita.tsx +30 -0
- package/templates/starter-jsx/src/layouts/base-layout/base-layout.script.ts +5 -0
- package/templates/starter-jsx/src/layouts/base-layout/index.ts +1 -0
- package/templates/starter-jsx/src/pages/404.css +1 -0
- package/templates/starter-jsx/src/pages/404.kita.tsx +19 -0
- package/templates/starter-jsx/src/pages/docs.mdx +31 -0
- package/templates/starter-jsx/src/pages/image.mdx +17 -0
- package/templates/starter-jsx/src/pages/index.css +30 -0
- package/templates/starter-jsx/src/pages/index.kita.tsx +54 -0
- package/templates/starter-jsx/src/public/android-chrome-192x192.png +0 -0
- package/templates/starter-jsx/src/public/android-chrome-512x512.png +0 -0
- package/templates/starter-jsx/src/public/apple-touch-icon.png +0 -0
- package/templates/starter-jsx/src/public/favicon-16x16.png +0 -0
- package/templates/starter-jsx/src/public/favicon-32x32.png +0 -0
- package/templates/starter-jsx/src/public/favicon.ico +0 -0
- package/templates/starter-jsx/src/public/site.webmanifest +19 -0
- package/templates/starter-jsx/src/styles/tailwind.css +106 -0
- package/templates/starter-jsx/tsconfig.json +27 -0
- package/templates/starter-lit-jsx/.env.example +4 -0
- package/templates/starter-lit-jsx/README.md +48 -0
- package/templates/starter-lit-jsx/app.ts +6 -0
- package/templates/starter-lit-jsx/eco.config.ts +32 -0
- package/templates/starter-lit-jsx/modules.d.ts +4 -0
- package/templates/starter-lit-jsx/package.json +26 -0
- package/templates/starter-lit-jsx/src/components/card/card.css +3 -0
- package/templates/starter-lit-jsx/src/components/card/card.kita.tsx +24 -0
- package/templates/starter-lit-jsx/src/components/card/index.ts +1 -0
- package/templates/starter-lit-jsx/src/components/lit-counter/index.ts +1 -0
- package/templates/starter-lit-jsx/src/components/lit-counter/lit-counter.css +10 -0
- package/templates/starter-lit-jsx/src/components/lit-counter/lit-counter.kita.tsx +10 -0
- package/templates/starter-lit-jsx/src/components/lit-counter/lit-counter.script.ts +38 -0
- package/templates/starter-lit-jsx/src/includes/head.kita.tsx +20 -0
- package/templates/starter-lit-jsx/src/includes/html.kita.tsx +20 -0
- package/templates/starter-lit-jsx/src/includes/seo.kita.tsx +28 -0
- package/templates/starter-lit-jsx/src/layouts/base-layout/base-layout.css +7 -0
- package/templates/starter-lit-jsx/src/layouts/base-layout/base-layout.kita.tsx +17 -0
- package/templates/starter-lit-jsx/src/layouts/base-layout/base-layout.script.ts +0 -0
- package/templates/starter-lit-jsx/src/layouts/base-layout/index.ts +1 -0
- package/templates/starter-lit-jsx/src/pages/404.css +1 -0
- package/templates/starter-lit-jsx/src/pages/404.kita.tsx +21 -0
- package/templates/starter-lit-jsx/src/pages/about.mdx +28 -0
- package/templates/starter-lit-jsx/src/pages/index.lit.tsx +28 -0
- package/templates/starter-lit-jsx/src/public/assets/favicon.svg +1 -0
- package/templates/starter-lit-jsx/src/public/assets/images/default-og.png +0 -0
- package/templates/starter-lit-jsx/src/public/assets/images/default-og.webp +0 -0
- package/templates/starter-lit-jsx/src/styles/tailwind.css +53 -0
- package/templates/starter-lit-jsx/tsconfig.json +27 -0
- package/templates/starter-react/.env.example +4 -0
- package/templates/starter-react/README.md +48 -0
- package/templates/starter-react/app.ts +6 -0
- package/templates/starter-react/eco.config.ts +30 -0
- package/templates/starter-react/modules.d.ts +3 -0
- package/templates/starter-react/package-lock.json +8598 -0
- package/templates/starter-react/package.json +34 -0
- package/templates/starter-react/src/components/counter.css +21 -0
- package/templates/starter-react/src/components/counter.tsx +36 -0
- package/templates/starter-react/src/includes/head.tsx +21 -0
- package/templates/starter-react/src/includes/html.tsx +21 -0
- package/templates/starter-react/src/includes/seo.tsx +28 -0
- package/templates/starter-react/src/layouts/base-layout/base-layout.css +7 -0
- package/templates/starter-react/src/layouts/base-layout/base-layout.script.ts +1 -0
- package/templates/starter-react/src/layouts/base-layout/base-layout.tsx +23 -0
- package/templates/starter-react/src/layouts/base-layout/index.ts +1 -0
- package/templates/starter-react/src/pages/404.css +1 -0
- package/templates/starter-react/src/pages/404.tsx +22 -0
- package/templates/starter-react/src/pages/index.css +20 -0
- package/templates/starter-react/src/pages/index.tsx +129 -0
- package/templates/starter-react/src/public/assets/favicon.svg +1 -0
- package/templates/starter-react/src/public/assets/images/default-og.png +0 -0
- package/templates/starter-react/src/public/assets/images/default-og.webp +0 -0
- package/templates/starter-react/src/styles/tailwind.css +2 -0
- package/templates/starter-react/tsconfig.json +20 -0
- package/templates/with-react-better-auth/.env.example +4 -0
- package/templates/with-react-better-auth/README.md +146 -0
- package/templates/with-react-better-auth/app.ts +11 -0
- package/templates/with-react-better-auth/drizzle.config.ts +10 -0
- package/templates/with-react-better-auth/eco.config.ts +66 -0
- package/templates/with-react-better-auth/modules.d.ts +13 -0
- package/templates/with-react-better-auth/package.json +41 -0
- package/templates/with-react-better-auth/src/components/announcement-bar.css +48 -0
- package/templates/with-react-better-auth/src/components/announcement-bar.tsx +51 -0
- package/templates/with-react-better-auth/src/components/auth-nav.css +7 -0
- package/templates/with-react-better-auth/src/components/auth-nav.tsx +57 -0
- package/templates/with-react-better-auth/src/components/dashboard-content.css +31 -0
- package/templates/with-react-better-auth/src/components/dashboard-content.tsx +42 -0
- package/templates/with-react-better-auth/src/components/icons.tsx +67 -0
- package/templates/with-react-better-auth/src/components/login-form.css +15 -0
- package/templates/with-react-better-auth/src/components/login-form.tsx +92 -0
- package/templates/with-react-better-auth/src/components/signup-form.css +19 -0
- package/templates/with-react-better-auth/src/components/signup-form.tsx +105 -0
- package/templates/with-react-better-auth/src/components/theme-toggle.tsx +48 -0
- package/templates/with-react-better-auth/src/handlers/auth.server.ts +19 -0
- package/templates/with-react-better-auth/src/handlers/dashboard.ts +18 -0
- package/templates/with-react-better-auth/src/images/.gitkeep +0 -0
- package/templates/with-react-better-auth/src/includes/head.tsx +21 -0
- package/templates/with-react-better-auth/src/includes/html.tsx +29 -0
- package/templates/with-react-better-auth/src/includes/seo.tsx +24 -0
- package/templates/with-react-better-auth/src/layouts/base-layout.css +39 -0
- package/templates/with-react-better-auth/src/layouts/base-layout.tsx +40 -0
- package/templates/with-react-better-auth/src/lib/auth-client.ts +5 -0
- package/templates/with-react-better-auth/src/lib/auth.server.ts +20 -0
- package/templates/with-react-better-auth/src/lib/db.server.ts +6 -0
- package/templates/with-react-better-auth/src/lib/migrate.ts +11 -0
- package/templates/with-react-better-auth/src/lib/schema.ts +55 -0
- package/templates/with-react-better-auth/src/pages/404.tsx +21 -0
- package/templates/with-react-better-auth/src/pages/dashboard.tsx +37 -0
- package/templates/with-react-better-auth/src/pages/index.tsx +61 -0
- package/templates/with-react-better-auth/src/pages/login.tsx +27 -0
- package/templates/with-react-better-auth/src/pages/signup.tsx +27 -0
- package/templates/with-react-better-auth/src/pages/skills.mdx +1067 -0
- package/templates/with-react-better-auth/src/public/android-chrome-192x192.png +0 -0
- package/templates/with-react-better-auth/src/public/android-chrome-512x512.png +0 -0
- package/templates/with-react-better-auth/src/public/apple-touch-icon.png +0 -0
- package/templates/with-react-better-auth/src/public/favicon-16x16.png +0 -0
- package/templates/with-react-better-auth/src/public/favicon-32x32.png +0 -0
- package/templates/with-react-better-auth/src/public/favicon.ico +0 -0
- package/templates/with-react-better-auth/src/public/site.webmanifest +19 -0
- package/templates/with-react-better-auth/src/styles/app.css +187 -0
- package/templates/with-react-better-auth/src/styles/router.css +15 -0
- package/templates/with-react-better-auth/tsconfig.json +16 -0
- package/CHANGELOG.md +0 -15
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ecopages",
|
|
3
|
-
"version": "0.2.0-alpha.
|
|
3
|
+
"version": "0.2.0-alpha.33",
|
|
4
4
|
"description": "CLI utilities for Ecopages",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"ecopages": "bin/cli.js"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@ecopages/core": "0.2.0-alpha.
|
|
32
|
+
"@ecopages/core": "0.2.0-alpha.33",
|
|
33
33
|
"@ecopages/logger": "^0.2.2",
|
|
34
34
|
"citty": "^0.1.6",
|
|
35
35
|
"giget": "^2.0.0",
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { ConfigBuilder } from '@ecopages/core/config-builder';
|
|
3
|
+
import { kitajsPlugin } from '@ecopages/kitajs';
|
|
4
|
+
import { mdxPlugin } from '@ecopages/mdx';
|
|
5
|
+
import { imageProcessorPlugin } from '@ecopages/image-processor';
|
|
6
|
+
import { postcssProcessorPlugin } from '@ecopages/postcss-processor';
|
|
7
|
+
import { tailwindV4Preset } from '@ecopages/postcss-processor/presets/tailwind-v4';
|
|
8
|
+
|
|
9
|
+
const config = await new ConfigBuilder()
|
|
10
|
+
.setRootDir(process.cwd())
|
|
11
|
+
.setBaseUrl(process.env.ECOPAGES_BASE_URL || 'http://localhost:3000')
|
|
12
|
+
.setIntegrations([
|
|
13
|
+
kitajsPlugin(),
|
|
14
|
+
mdxPlugin({
|
|
15
|
+
compilerOptions: {
|
|
16
|
+
jsxImportSource: '@kitajs/html',
|
|
17
|
+
},
|
|
18
|
+
}),
|
|
19
|
+
])
|
|
20
|
+
.setProcessors([
|
|
21
|
+
imageProcessorPlugin({
|
|
22
|
+
options: {
|
|
23
|
+
sourceDir: path.resolve(process.cwd(), 'src/images'),
|
|
24
|
+
outputDir: path.resolve(process.cwd(), 'dist/images'),
|
|
25
|
+
publicPath: '/images',
|
|
26
|
+
acceptedFormats: ['jpg', 'jpeg', 'png', 'webp'],
|
|
27
|
+
quality: 80,
|
|
28
|
+
format: 'webp',
|
|
29
|
+
sizes: [
|
|
30
|
+
{ width: 320, label: 'sm' },
|
|
31
|
+
{ width: 768, label: 'md' },
|
|
32
|
+
{ width: 1024, label: 'lg' },
|
|
33
|
+
{ width: 1920, label: 'xl' },
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
}),
|
|
37
|
+
postcssProcessorPlugin(
|
|
38
|
+
tailwindV4Preset({
|
|
39
|
+
referencePath: path.resolve(process.cwd(), 'src/styles/tailwind.css'),
|
|
40
|
+
}),
|
|
41
|
+
),
|
|
42
|
+
])
|
|
43
|
+
.build();
|
|
44
|
+
|
|
45
|
+
export default config;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "blog-jsx",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"start": "ecopages start",
|
|
7
|
+
"dev": "ecopages dev",
|
|
8
|
+
"build": "ecopages build",
|
|
9
|
+
"preview": "ecopages preview",
|
|
10
|
+
"dev:watch": "ecopages dev:watch"
|
|
11
|
+
},
|
|
12
|
+
"devDependencies": {
|
|
13
|
+
"ecopages": "0.2.0-alpha.33",
|
|
14
|
+
"@ecopages/core": "0.2.0-alpha.33",
|
|
15
|
+
"@ecopages/kitajs": "0.2.0-alpha.33",
|
|
16
|
+
"@ecopages/lit": "0.2.0-alpha.33",
|
|
17
|
+
"@ecopages/mdx": "0.2.0-alpha.33",
|
|
18
|
+
"@ecopages/image-processor": "0.2.0-alpha.33",
|
|
19
|
+
"@ecopages/postcss-processor": "0.2.0-alpha.33",
|
|
20
|
+
"@ecopages/browser-router": "0.2.0-alpha.33",
|
|
21
|
+
"@ecopages/scripts-injector": "latest",
|
|
22
|
+
"@kitajs/html": "^4.2.13",
|
|
23
|
+
"@tailwindcss/postcss": "^4.1.18",
|
|
24
|
+
"tailwindcss": "^4.1.18",
|
|
25
|
+
"@ecopages/radiant": "0.3.0-alpha.16"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
type IconProps = {
|
|
2
|
+
class?: string;
|
|
3
|
+
size?: number;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
export const Moon = ({ class: className, size = 24 }: IconProps) => (
|
|
7
|
+
<svg
|
|
8
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
9
|
+
width={size}
|
|
10
|
+
height={size}
|
|
11
|
+
viewBox="0 0 24 24"
|
|
12
|
+
fill="none"
|
|
13
|
+
stroke="currentColor"
|
|
14
|
+
stroke-width="2"
|
|
15
|
+
stroke-linecap="round"
|
|
16
|
+
stroke-linejoin="round"
|
|
17
|
+
class={className}
|
|
18
|
+
>
|
|
19
|
+
<path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" />
|
|
20
|
+
</svg>
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
export const Sun = ({ class: className, size = 24 }: IconProps) => (
|
|
24
|
+
<svg
|
|
25
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
26
|
+
width={size}
|
|
27
|
+
height={size}
|
|
28
|
+
viewBox="0 0 24 24"
|
|
29
|
+
fill="none"
|
|
30
|
+
stroke="currentColor"
|
|
31
|
+
stroke-width="2"
|
|
32
|
+
stroke-linecap="round"
|
|
33
|
+
stroke-linejoin="round"
|
|
34
|
+
class={className}
|
|
35
|
+
>
|
|
36
|
+
<circle cx="12" cy="12" r="4" />
|
|
37
|
+
<path d="M12 2v2" />
|
|
38
|
+
<path d="M12 20v2" />
|
|
39
|
+
<path d="m4.93 4.93 1.41 1.41" />
|
|
40
|
+
<path d="m17.66 17.66 1.41 1.41" />
|
|
41
|
+
<path d="M2 12h2" />
|
|
42
|
+
<path d="M20 12h2" />
|
|
43
|
+
<path d="m6.34 17.66-1.41 1.41" />
|
|
44
|
+
<path d="m19.07 4.93-1.41 1.41" />
|
|
45
|
+
</svg>
|
|
46
|
+
);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
.theme-toggle {
|
|
2
|
+
appearance: none;
|
|
3
|
+
border: 1px solid var(--color-border);
|
|
4
|
+
background: var(--color-surface-elevated);
|
|
5
|
+
border-radius: 0.375rem;
|
|
6
|
+
padding: 0.375rem 0.625rem;
|
|
7
|
+
font-size: var(--text-base);
|
|
8
|
+
cursor: pointer;
|
|
9
|
+
transition:
|
|
10
|
+
border-color 0.15s ease,
|
|
11
|
+
background-color 0.2s ease;
|
|
12
|
+
display: inline-flex;
|
|
13
|
+
align-items: center;
|
|
14
|
+
justify-content: center;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.theme-toggle:hover {
|
|
18
|
+
border-color: var(--color-accent);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.dark .theme-toggle-sun {
|
|
22
|
+
display: inline-flex;
|
|
23
|
+
}
|
|
24
|
+
.dark .theme-toggle-moon {
|
|
25
|
+
display: none;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.theme-toggle-sun {
|
|
29
|
+
display: none;
|
|
30
|
+
}
|
|
31
|
+
.theme-toggle-moon {
|
|
32
|
+
display: inline-flex;
|
|
33
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { eco } from '@ecopages/core';
|
|
2
|
+
import { Moon, Sun } from './icons.kita';
|
|
3
|
+
|
|
4
|
+
export const ThemeToggle = eco.component({
|
|
5
|
+
dependencies: {
|
|
6
|
+
stylesheets: ['./theme-toggle.css'],
|
|
7
|
+
scripts: ['./theme-toggle.script.ts'],
|
|
8
|
+
},
|
|
9
|
+
|
|
10
|
+
render: () => {
|
|
11
|
+
return (
|
|
12
|
+
<theme-toggle class="theme-toggle" aria-label="Toggle theme" data-eco-persist="theme-toggle">
|
|
13
|
+
<span class="theme-toggle-sun">
|
|
14
|
+
<Sun size={18} />
|
|
15
|
+
</span>
|
|
16
|
+
<span class="theme-toggle-moon">
|
|
17
|
+
<Moon size={18} />
|
|
18
|
+
</span>
|
|
19
|
+
</theme-toggle>
|
|
20
|
+
);
|
|
21
|
+
},
|
|
22
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { customElement } from '@ecopages/radiant/decorators/custom-element';
|
|
2
|
+
import { RadiantElement } from '@ecopages/radiant';
|
|
3
|
+
|
|
4
|
+
@customElement('theme-toggle')
|
|
5
|
+
export class ThemeToggleElement extends RadiantElement {
|
|
6
|
+
override connectedCallback(): void {
|
|
7
|
+
super.connectedCallback();
|
|
8
|
+
this.initTheme();
|
|
9
|
+
this.addEventListener('click', this.handleClick.bind(this));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
handleClick() {
|
|
13
|
+
const isDark = document.documentElement.classList.contains('dark');
|
|
14
|
+
const next = !isDark;
|
|
15
|
+
this.updateTheme(next);
|
|
16
|
+
localStorage.setItem('theme', next ? 'dark' : 'light');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
initTheme() {
|
|
20
|
+
const storedTheme = localStorage.getItem('theme');
|
|
21
|
+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
22
|
+
const isDark = storedTheme ? storedTheme === 'dark' : prefersDark;
|
|
23
|
+
this.updateTheme(isDark);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
updateTheme(isDark: boolean) {
|
|
27
|
+
document.documentElement.classList.toggle('dark', isDark);
|
|
28
|
+
document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light');
|
|
29
|
+
this.setAttribute('aria-label', isDark ? 'Switch to light mode' : 'Switch to dark mode');
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
declare global {
|
|
34
|
+
namespace JSX {
|
|
35
|
+
interface IntrinsicElements {
|
|
36
|
+
'theme-toggle': HtmlTag;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { eco } from '@ecopages/core';
|
|
2
|
+
import type { PageHeadProps } from '@ecopages/core';
|
|
3
|
+
import { Seo } from '@/includes/seo.kita';
|
|
4
|
+
|
|
5
|
+
export const Head = eco.component<PageHeadProps>({
|
|
6
|
+
dependencies: {
|
|
7
|
+
stylesheets: ['../styles/tailwind.css'],
|
|
8
|
+
},
|
|
9
|
+
|
|
10
|
+
render: ({ metadata, children }) => {
|
|
11
|
+
return (
|
|
12
|
+
<head>
|
|
13
|
+
<meta charset="UTF-8" />
|
|
14
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
15
|
+
<Seo {...metadata} />
|
|
16
|
+
{children}
|
|
17
|
+
</head>
|
|
18
|
+
);
|
|
19
|
+
},
|
|
20
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { eco } from '@ecopages/core';
|
|
2
|
+
import type { HtmlTemplateProps } from '@ecopages/core';
|
|
3
|
+
import { Head } from '@/includes/head.kita';
|
|
4
|
+
|
|
5
|
+
const themeScript = `(function(){const t=localStorage.getItem('theme')||(window.matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light');document.documentElement.setAttribute('data-theme',t);if(t==='dark'){document.documentElement.classList.add('dark')}else{document.documentElement.classList.remove('dark')}})();`;
|
|
6
|
+
|
|
7
|
+
const HtmlTemplate = eco.component<HtmlTemplateProps>({
|
|
8
|
+
dependencies: {
|
|
9
|
+
components: [Head],
|
|
10
|
+
},
|
|
11
|
+
|
|
12
|
+
render: ({ children, metadata, headContent, language = 'en' }) => {
|
|
13
|
+
return (
|
|
14
|
+
<html lang={language}>
|
|
15
|
+
<Head metadata={metadata}>
|
|
16
|
+
{
|
|
17
|
+
(
|
|
18
|
+
<>
|
|
19
|
+
<script>{themeScript}</script>
|
|
20
|
+
{headContent}
|
|
21
|
+
</>
|
|
22
|
+
) as 'safe'
|
|
23
|
+
}
|
|
24
|
+
</Head>
|
|
25
|
+
<body>{children as 'safe'}</body>
|
|
26
|
+
</html>
|
|
27
|
+
);
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
export default HtmlTemplate;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { PageMetadataProps } from '@ecopages/core';
|
|
2
|
+
|
|
3
|
+
const baseUrl = process.env.ECOPAGES_BASE_URL ?? 'http://localhost:3000';
|
|
4
|
+
const withBaseUrl = (path: string) => `${baseUrl}/${path.replace(/^\//u, '')}`;
|
|
5
|
+
|
|
6
|
+
export function Seo({
|
|
7
|
+
title,
|
|
8
|
+
description,
|
|
9
|
+
image = '/assets/images/default-og.webp',
|
|
10
|
+
url,
|
|
11
|
+
keywords,
|
|
12
|
+
}: PageMetadataProps) {
|
|
13
|
+
return (
|
|
14
|
+
<>
|
|
15
|
+
<title>{title}</title>
|
|
16
|
+
<link rel="icon" type="image/x-icon" href="/assets/favicon.svg" />
|
|
17
|
+
<link rel="robots" href="/robots.txt" />
|
|
18
|
+
<meta name="description" content={description} />
|
|
19
|
+
{keywords?.length ? <meta name="keywords" content={keywords.join(',')} /> : null}
|
|
20
|
+
<meta property="og:title" content={title} />
|
|
21
|
+
<meta property="og:description" content={description} />
|
|
22
|
+
<meta property="og:image" content={withBaseUrl(image)} />
|
|
23
|
+
<meta name="twitter:title" content={title} />
|
|
24
|
+
<meta name="twitter:description" content={description} />
|
|
25
|
+
{url ? <link rel="canonical" href={withBaseUrl(url)} /> : null}
|
|
26
|
+
</>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
.layout-container {
|
|
2
|
+
@apply min-h-screen bg-surface text-text font-sans antialiased selection:bg-accent-subtle selection:text-accent flex flex-col;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.site-header {
|
|
6
|
+
@apply max-w-3xl mx-auto w-full border-border border-b bg-surface/80 backdrop-blur-sm sticky top-0 z-50 transition-all duration-300;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.header-content {
|
|
10
|
+
@apply max-w-3xl mx-auto px-6 h-16 flex items-center justify-between;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.logo {
|
|
14
|
+
@apply font-serif text-xl font-bold tracking-tight text-text no-underline;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.main-content {
|
|
18
|
+
@apply max-w-3xl mx-auto px-6 py-12 w-full grow;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.site-footer {
|
|
22
|
+
@apply max-w-3xl mx-auto px-6 py-8 w-full border-t border-border mt-auto flex flex-col sm:flex-row justify-between items-center gap-4 text-sm text-text-muted;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.footer-link {
|
|
26
|
+
@apply hover:text-link transition-colors;
|
|
27
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { eco } from '@ecopages/core';
|
|
2
|
+
import { ThemeToggle } from '@/components/theme-toggle.kita';
|
|
3
|
+
|
|
4
|
+
export type BaseLayoutProps = {
|
|
5
|
+
children: JSX.Element | JSX.Element[];
|
|
6
|
+
id?: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const BaseLayout = eco.component<BaseLayoutProps>({
|
|
10
|
+
dependencies: {
|
|
11
|
+
stylesheets: ['./base-layout.css'],
|
|
12
|
+
scripts: ['./base-layout.script.ts'],
|
|
13
|
+
components: [ThemeToggle],
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
render: ({ children }) => {
|
|
17
|
+
return (
|
|
18
|
+
<div class="layout-container">
|
|
19
|
+
<header class="site-header">
|
|
20
|
+
<div class="header-content">
|
|
21
|
+
<a href="/" class="logo">
|
|
22
|
+
EcoBlog
|
|
23
|
+
</a>
|
|
24
|
+
<ThemeToggle />
|
|
25
|
+
</div>
|
|
26
|
+
</header>
|
|
27
|
+
<main class="main-content">{children as 'safe'}</main>
|
|
28
|
+
<footer class="site-footer">
|
|
29
|
+
<p>{'© ' + new Date().getFullYear()} EcoBlog. Built with EcoPages.</p>
|
|
30
|
+
<a
|
|
31
|
+
href="https://github.com/ecopages/ecopages"
|
|
32
|
+
target="_blank"
|
|
33
|
+
rel="noopener noreferrer"
|
|
34
|
+
class="footer-link"
|
|
35
|
+
>
|
|
36
|
+
GitHub
|
|
37
|
+
</a>
|
|
38
|
+
</footer>
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
},
|
|
42
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
.error404 {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
align-items: center;
|
|
5
|
+
justify-content: center;
|
|
6
|
+
gap: var(--space);
|
|
7
|
+
padding: var(--space-lg);
|
|
8
|
+
margin: var(--space-lg) auto;
|
|
9
|
+
max-width: fit-content;
|
|
10
|
+
background: var(--color-surface-elevated);
|
|
11
|
+
border: 1px solid var(--color-border);
|
|
12
|
+
border-radius: 0.5rem;
|
|
13
|
+
transition:
|
|
14
|
+
background-color 0.2s ease,
|
|
15
|
+
border-color 0.2s ease;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.error404 h1 {
|
|
19
|
+
margin-bottom: 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.error404 p {
|
|
23
|
+
margin-bottom: 0;
|
|
24
|
+
padding: var(--space);
|
|
25
|
+
background: var(--color-surface-muted);
|
|
26
|
+
border-radius: 0.375rem;
|
|
27
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { eco } from '@ecopages/core';
|
|
2
|
+
import type { Error404TemplateProps } from '@ecopages/core';
|
|
3
|
+
import { BaseLayout } from '@/layouts/base-layout/base-layout.kita';
|
|
4
|
+
|
|
5
|
+
export default eco.page<Error404TemplateProps>({
|
|
6
|
+
dependencies: {
|
|
7
|
+
stylesheets: ['./404.css'],
|
|
8
|
+
components: [BaseLayout],
|
|
9
|
+
},
|
|
10
|
+
|
|
11
|
+
render: () => {
|
|
12
|
+
return (
|
|
13
|
+
<BaseLayout>
|
|
14
|
+
<div class="error404">
|
|
15
|
+
<h1>404 - Page Not Found</h1>
|
|
16
|
+
<p>The page you are looking for does not exist.</p>
|
|
17
|
+
</div>
|
|
18
|
+
</BaseLayout>
|
|
19
|
+
);
|
|
20
|
+
},
|
|
21
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { eco } from '@ecopages/core';
|
|
2
|
+
import { BaseLayout } from '@/layouts/base-layout/base-layout.kita';
|
|
3
|
+
|
|
4
|
+
export default eco.page({
|
|
5
|
+
layout: BaseLayout,
|
|
6
|
+
|
|
7
|
+
metadata: () => ({
|
|
8
|
+
title: 'About | Blog',
|
|
9
|
+
description: 'About the EcoPages Browser Router project',
|
|
10
|
+
}),
|
|
11
|
+
|
|
12
|
+
render: () => {
|
|
13
|
+
return (
|
|
14
|
+
<>
|
|
15
|
+
<a href="/" class="back-link">
|
|
16
|
+
← Back to Blog
|
|
17
|
+
</a>
|
|
18
|
+
|
|
19
|
+
<article class="post-content">
|
|
20
|
+
<h1>About This Project</h1>
|
|
21
|
+
<p>
|
|
22
|
+
This is a proof-of-concept for SPA navigation in EcoPages using the Browser Router. We fetch
|
|
23
|
+
full HTML, morph the DOM, and support View Transitions without a full page reload.
|
|
24
|
+
</p>
|
|
25
|
+
</article>
|
|
26
|
+
|
|
27
|
+
<div style="margin-top: 3rem"></div>
|
|
28
|
+
</>
|
|
29
|
+
);
|
|
30
|
+
},
|
|
31
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
.post-card {
|
|
2
|
+
@apply my-6;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.post-card-link {
|
|
6
|
+
@apply flex flex-col sm:flex-row gap-4 no-underline text-inherit items-start transition-opacity duration-200;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.post-card-link:hover {
|
|
10
|
+
@apply opacity-80;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.post-card-link img {
|
|
14
|
+
@apply transition-transform duration-300;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.post-card-link:hover img {
|
|
18
|
+
@apply scale-105;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.post-card-image {
|
|
22
|
+
@apply shrink-0 w-full h-[240px] sm:w-[200px] sm:h-[140px] overflow-hidden rounded-lg shadow-sm;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.post-card-image img {
|
|
26
|
+
@apply w-full h-full object-cover;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.post-card-text {
|
|
30
|
+
@apply flex flex-col gap-2;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.post-card h2 {
|
|
34
|
+
@apply m-0 text-xl font-bold tracking-tight text-text transition-colors duration-200;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.post-card-link:hover h2 {
|
|
38
|
+
@apply text-accent-hover;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.post-card p {
|
|
42
|
+
@apply m-0 text-sm text-text-muted leading-relaxed;
|
|
43
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { eco } from '@ecopages/core';
|
|
2
|
+
import { BaseLayout } from '@/layouts/base-layout/base-layout.kita';
|
|
3
|
+
import { EcoImage } from '@ecopages/image-processor/component/html';
|
|
4
|
+
import {
|
|
5
|
+
ezi76Gu53NklsuUnsplashJpg,
|
|
6
|
+
theodorePoncetQzephogqd7WUnsplashJpg,
|
|
7
|
+
urbanVintage78A265Wpio4UnsplashJpg,
|
|
8
|
+
} from 'ecopages:images';
|
|
9
|
+
|
|
10
|
+
const posts = [
|
|
11
|
+
{
|
|
12
|
+
slug: 'hello-world',
|
|
13
|
+
title: 'Hello World',
|
|
14
|
+
excerpt: 'Welcome to EcoPages!',
|
|
15
|
+
image: ezi76Gu53NklsuUnsplashJpg,
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
slug: 'browser-router',
|
|
19
|
+
title: 'Building a Browser Router',
|
|
20
|
+
excerpt: 'How we built SPA navigation.',
|
|
21
|
+
image: theodorePoncetQzephogqd7WUnsplashJpg,
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
slug: 'ssr-benefits',
|
|
25
|
+
title: 'SSR Benefits',
|
|
26
|
+
excerpt: 'Why server-side rendering matters.',
|
|
27
|
+
image: urbanVintage78A265Wpio4UnsplashJpg,
|
|
28
|
+
},
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
export default eco.page({
|
|
32
|
+
layout: BaseLayout,
|
|
33
|
+
|
|
34
|
+
dependencies: {
|
|
35
|
+
stylesheets: ['./index.css'],
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
metadata: () => ({
|
|
39
|
+
title: 'Blog | EcoPages',
|
|
40
|
+
description: 'A simple blog built with EcoPages Browser Router',
|
|
41
|
+
}),
|
|
42
|
+
|
|
43
|
+
render: () => {
|
|
44
|
+
return (
|
|
45
|
+
<>
|
|
46
|
+
<h1>Welcome</h1>
|
|
47
|
+
<p>A minimal blog exploring EcoPages with SPA navigation.</p>
|
|
48
|
+
|
|
49
|
+
{posts.map((post) => (
|
|
50
|
+
<article class="post-card">
|
|
51
|
+
<a href={`/posts/${post.slug}`} class="post-card-link">
|
|
52
|
+
<div class="post-card-image" data-view-transition={`hero-image-${post.slug}`}>
|
|
53
|
+
<EcoImage {...post.image} alt={post.title} />
|
|
54
|
+
</div>
|
|
55
|
+
<div class="post-card-content">
|
|
56
|
+
<h2>{post.title}</h2>
|
|
57
|
+
<p>{post.excerpt}</p>
|
|
58
|
+
</div>
|
|
59
|
+
</a>
|
|
60
|
+
</article>
|
|
61
|
+
))}
|
|
62
|
+
<article class="post-card">
|
|
63
|
+
<a href="/about" class="post-card-link">
|
|
64
|
+
<div class="post-card-content">
|
|
65
|
+
<h2>About This Project</h2>
|
|
66
|
+
<p>Learn about the EcoPages Browser Router.</p>
|
|
67
|
+
</div>
|
|
68
|
+
</a>
|
|
69
|
+
</article>
|
|
70
|
+
<article class="post-card">
|
|
71
|
+
<a href="/mdx-example" class="post-card-link">
|
|
72
|
+
<div class="post-card-content">
|
|
73
|
+
<h2>MDX Example</h2>
|
|
74
|
+
<p>See how MDX works with the Browser Router.</p>
|
|
75
|
+
</div>
|
|
76
|
+
</a>
|
|
77
|
+
</article>
|
|
78
|
+
|
|
79
|
+
<div style="margin-top: 3rem"></div>
|
|
80
|
+
</>
|
|
81
|
+
);
|
|
82
|
+
},
|
|
83
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { BaseLayout } from '@/layouts/base-layout/base-layout.kita';
|
|
2
|
+
|
|
3
|
+
export const config = {
|
|
4
|
+
layout: BaseLayout,
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const getMetadata = () => ({
|
|
8
|
+
title: 'MDX Example | Blog',
|
|
9
|
+
description: 'An example MDX page with the EcoPages Browser Router',
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
<a href="/" class="back-link">← Back to Blog</a>
|
|
13
|
+
|
|
14
|
+
# Writing with MDX
|
|
15
|
+
|
|
16
|
+
This page is written in **MDX** - a powerful combination of Markdown and JSX.
|
|
17
|
+
|
|
18
|
+
## Why MDX?
|
|
19
|
+
|
|
20
|
+
MDX lets you:
|
|
21
|
+
|
|
22
|
+
- Write content in familiar Markdown syntax
|
|
23
|
+
- Embed components directly in your content
|
|
24
|
+
- Use JavaScript expressions inline
|
|
25
|
+
|
|
26
|
+
## Code Example
|
|
27
|
+
|
|
28
|
+
Here's some code with syntax highlighting:
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
const greeting = "Hello from MDX!";
|
|
32
|
+
|
|
33
|
+
export const MyComponent = () => (
|
|
34
|
+
<div>{greeting}</div>
|
|
35
|
+
);
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Navigation
|
|
39
|
+
|
|
40
|
+
Check out the other pages:
|
|
41
|
+
|
|
42
|
+
- [Home](/)
|
|
43
|
+
- [About](/about)
|
|
44
|
+
- [Hello World Post](/posts/hello-world)
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
*This page demonstrates that MDX works seamlessly with the Browser Router SPA navigation.*
|