astro-blog-kit 0.3.5 → 0.3.7

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.
@@ -12,8 +12,8 @@ const pages = Array.from({ length: totalPages }, (_, i) => i + 1);
12
12
  <nav class="pagination" aria-label="Blog pagination">
13
13
 
14
14
  {currentPage > 1 && (
15
-
16
- <a href={currentPage === 2 ? blogBase : `${basePath}${currentPage - 1}/`}
15
+ <a
16
+ href={currentPage === 2 ? blogBase : `${basePath}${currentPage - 1}/`}
17
17
  class="pagination__btn"
18
18
  >
19
19
  ← {t.blog.btn_prev}
@@ -22,8 +22,8 @@ const pages = Array.from({ length: totalPages }, (_, i) => i + 1);
22
22
 
23
23
  <div class="pagination__pages">
24
24
  {pages.map((pageNum) => (
25
-
26
- <a href={pageNum === 1 ? blogBase : `${basePath}${pageNum}/`}
25
+ <a
26
+ href={pageNum === 1 ? blogBase : `${basePath}${pageNum}/`}
27
27
  class={`pagination__page ${pageNum === currentPage ? "pagination__page--active" : ""}`}
28
28
  aria-current={pageNum === currentPage ? "page" : undefined}
29
29
  >
@@ -49,25 +49,25 @@ const pages = Array.from({ length: totalPages }, (_, i) => i + 1);
49
49
  gap: 0.75rem;
50
50
  flex-wrap: wrap;
51
51
  padding-top: 3rem;
52
- border-top: 2px solid var(--bk-gray-200);
52
+ border-top: 2px solid var(--bk-border);
53
53
  }
54
54
 
55
55
  .pagination__btn {
56
56
  padding: 0.6rem 1.25rem;
57
- background-color: var(--bk-black);
58
- color: var(--bk-white);
57
+ background-color: var(--bk-pagination-btn-bg);
58
+ color: var(--bk-pagination-btn-text);
59
59
  font-family: var(--bk-font-heading);
60
60
  font-size: 0.9rem;
61
61
  font-weight: 700;
62
62
  text-transform: uppercase;
63
63
  letter-spacing: 0.08em;
64
64
  text-decoration: none;
65
- transition: background-color 0.2s ease, color 0.2s ease;
65
+ transition: var(--bk-transition);
66
66
  }
67
67
 
68
68
  .pagination__btn:hover {
69
- background-color: var(--bk-yellow);
70
- color: var(--bk-black);
69
+ background-color: var(--bk-pagination-btn-hover-bg);
70
+ color: var(--bk-pagination-btn-hover-text);
71
71
  }
72
72
 
73
73
  .pagination__pages {
@@ -83,19 +83,19 @@ const pages = Array.from({ length: totalPages }, (_, i) => i + 1);
83
83
  font-weight: 700;
84
84
  font-size: 0.9rem;
85
85
  color: var(--bk-muted);
86
- border: 2px solid var(--bk-gray-200);
86
+ border: 2px solid var(--bk-border);
87
87
  text-decoration: none;
88
- transition: border-color 0.2s ease, color 0.2s ease;
88
+ transition: var(--bk-transition);
89
89
  }
90
90
 
91
91
  .pagination__page:hover {
92
- border-color: var(--bk-black);
93
- color: var(--bk-black);
92
+ border-color: var(--bk-pagination-btn-bg);
93
+ color: var(--bk-text);
94
94
  }
95
95
 
96
96
  .pagination__page--active {
97
- background-color: var(--bk-yellow);
98
- border-color: var(--bk-yellow);
99
- color: var(--bk-black);
97
+ background-color: var(--bk-pagination-active-bg);
98
+ border-color: var(--bk-pagination-active-bg);
99
+ color: var(--bk-pagination-active-text);
100
100
  }
101
101
  </style>
package/integration.ts CHANGED
@@ -4,140 +4,108 @@
4
4
 
5
5
  import type { AstroIntegration } from "astro";
6
6
  import type { Plugin } from "vite";
7
- import type { BlogKitConfig, BlogTheme } from "./types";
8
-
9
- const VIRTUAL_MODULE_ID = "virtual:astro-blog-kit/theme";
10
- const RESOLVED_VIRTUAL_MODULE_ID = "\0" + VIRTUAL_MODULE_ID;
7
+ import type { BlogKitConfig, BlogTheme, BlogUI } from "./types";
11
8
 
12
9
  /**
13
- * Genera el bloque de CSS variables a partir del tema.
10
+ * Genera el bloque de CSS variables a partir del tema y la UI.
14
11
  */
15
- function generateThemeCSS(theme: BlogTheme = {}): string {
12
+ function generateThemeCSS(theme: BlogTheme = {}, ui: BlogUI = {}): string {
16
13
  const t = {
17
- accent: theme.accent ?? "#facc15",
18
- background: theme.background ?? "#ffffff",
19
- surface: theme.surface ?? "#f8f8f8",
20
- text: theme.text ?? "#0a0a0a",
21
- muted: theme.muted ?? "#6b7280",
22
- mutedLight: theme.mutedLight ?? "#9ca3af",
23
- border: theme.border ?? "#e5e7eb",
24
- black: theme.black ?? "#0a0a0a",
25
- white: theme.white ?? "#ffffff",
26
- fontHeading: theme.fontHeading ?? "Georgia, serif",
27
- fontBody: theme.fontBody ?? "system-ui, sans-serif",
28
- fontMono: theme.fontMono ?? "monospace",
29
- fontDisplay: theme.fontDisplay ?? "Georgia, serif",
14
+ accent: theme.accent ?? "#facc15",
15
+ background: theme.background ?? "#ffffff",
16
+ surface: theme.surface ?? "#f8f8f8",
17
+ text: theme.text ?? "#0a0a0a",
18
+ muted: theme.muted ?? "#6b7280",
19
+ mutedLight: theme.mutedLight ?? "#9ca3af",
20
+ border: theme.border ?? "#e5e7eb",
21
+ black: theme.black ?? "#0a0a0a",
22
+ white: theme.white ?? "#ffffff",
23
+ fontHeading: theme.fontHeading ?? "Georgia, serif",
24
+ fontBody: theme.fontBody ?? "system-ui, sans-serif",
25
+ fontMono: theme.fontMono ?? "monospace",
26
+ fontDisplay: theme.fontDisplay ?? "Georgia, serif",
30
27
  containerMax: theme.containerMax ?? "1200px",
31
28
  };
32
29
 
33
- return `
34
- :root {
35
- --bk-accent: ${t.accent};
36
- --bk-background: ${t.background};
37
- --bk-surface: ${t.surface};
38
- --bk-text: ${t.text};
39
- --bk-muted: ${t.muted};
40
- --bk-muted-light: ${t.mutedLight};
41
- --bk-border: ${t.border};
42
- --bk-black: ${t.black};
43
- --bk-white: ${t.white};
44
- --bk-yellow: ${t.accent};
45
- --bk-gray-100: #f3f4f6;
46
- --bk-gray-200: #e5e7eb;
47
- --bk-gray-300: #d1d5db;
48
- --bk-gray-400: #9ca3af;
49
- --bk-gray-600: #4b5563;
50
- --bk-font-heading: ${t.fontHeading};
51
- --bk-font-body: ${t.fontBody};
52
- --bk-font-mono: ${t.fontMono};
53
- --bk-font-display: ${t.fontDisplay};
54
- --bk-container-max: ${t.containerMax};
55
- --bk-transition: all 0.2s ease;
56
- }
57
-
58
- *, *::before, *::after {
59
- box-sizing: border-box;
60
- margin: 0;
61
- padding: 0;
62
- }
63
- `.trim();
30
+ return [
31
+ ":root {",
32
+ ` --bk-accent: ${t.accent};`,
33
+ ` --bk-background: ${t.background};`,
34
+ ` --bk-surface: ${t.surface};`,
35
+ ` --bk-text: ${t.text};`,
36
+ ` --bk-muted: ${t.muted};`,
37
+ ` --bk-muted-light: ${t.mutedLight};`,
38
+ ` --bk-border: ${t.border};`,
39
+ ` --bk-black: ${t.black};`,
40
+ ` --bk-white: ${t.white};`,
41
+ ` --bk-yellow: ${t.accent};`,
42
+ ` --bk-gray-100: #f3f4f6;`,
43
+ ` --bk-gray-200: #e5e7eb;`,
44
+ ` --bk-gray-300: #d1d5db;`,
45
+ ` --bk-gray-400: #9ca3af;`,
46
+ ` --bk-gray-600: #4b5563;`,
47
+ ` --bk-font-heading: ${t.fontHeading};`,
48
+ ` --bk-font-body: ${t.fontBody};`,
49
+ ` --bk-font-mono: ${t.fontMono};`,
50
+ ` --bk-font-display: ${t.fontDisplay};`,
51
+ ` --bk-container-max: ${t.containerMax};`,
52
+ ` --bk-transition: all 0.2s ease;`,
53
+ ` --bk-pagination-btn-bg: ${ui.paginationBtnBg ?? t.accent};`,
54
+ ` --bk-pagination-btn-text: ${ui.paginationBtnText ?? t.black};`,
55
+ ` --bk-pagination-btn-hover-bg: ${ui.paginationBtnHoverBg ?? t.text};`,
56
+ ` --bk-pagination-btn-hover-text: ${ui.paginationBtnHoverText ?? t.white};`,
57
+ ` --bk-pagination-active-bg: ${ui.paginationActiveBg ?? t.accent};`,
58
+ ` --bk-pagination-active-text: ${ui.paginationActiveText ?? t.black};`,
59
+ ` --bk-comment-btn-bg: ${ui.commentButtonColor ?? t.accent};`,
60
+ ` --bk-comment-btn-text: ${ui.commentButtonTextColor ?? t.black};`,
61
+ "}",
62
+ ].join("\n");
64
63
  }
65
64
 
66
65
  /**
67
- * Plugin de Vite que expone el tema como un virtual module CSS.
68
- * Esto permite que Astro procese el CSS en SSR correctamente,
69
- * sin depender de JavaScript en el cliente para inyectar variables.
70
- *
71
- * Uso en cualquier componente .astro del paquete:
72
- * import 'virtual:astro-blog-kit/theme';
66
+ * Plugin de Vite que inyecta el CSS del tema como módulo CSS real,
67
+ * compatible con Rolldown (Astro 7+).
73
68
  */
74
- function createThemePlugin(theme: BlogTheme): Plugin {
75
- const css = generateThemeCSS(theme);
69
+ function createThemePlugin(theme: BlogTheme, ui: BlogUI): Plugin {
70
+ const THEME_ID = "\0astro-blog-kit-theme.css";
71
+ const css = generateThemeCSS(theme, ui);
76
72
 
77
73
  return {
78
74
  name: "astro-blog-kit:theme",
75
+ enforce: "pre",
76
+
79
77
  resolveId(id) {
80
- if (id === VIRTUAL_MODULE_ID) {
81
- return RESOLVED_VIRTUAL_MODULE_ID;
78
+ if (id === "astro-blog-kit-theme.css") {
79
+ return THEME_ID;
82
80
  }
83
81
  },
82
+
84
83
  load(id) {
85
- if (id === RESOLVED_VIRTUAL_MODULE_ID) {
86
- // Retornamos CSS puro — Vite lo procesa como módulo CSS
87
- return `export default ${JSON.stringify(css)};`;
84
+ if (id === THEME_ID) {
85
+ return css;
86
+ }
87
+ },
88
+
89
+ transform(code, id) {
90
+ if (id === THEME_ID) {
91
+ return { code, map: null, meta: { vite: { lang: "css" } } };
88
92
  }
89
93
  },
90
- // Fuerza el tipo del módulo como CSS para que Vite lo trate correctamente
91
- // transform(code, id) {
92
- // if (id === RESOLVED_VIRTUAL_MODULE_ID) {
93
- // return {
94
- // code: `
95
- // const style = document.createElement('style');
96
- // style.id = 'astro-blog-kit-theme';
97
- // style.textContent = ${JSON.stringify(css)};
98
- // if (!document.getElementById('astro-blog-kit-theme')) {
99
- // document.head.appendChild(style);
100
- // }
101
- // `.trim(),
102
- // map: null,
103
- // };
104
- // }
105
- // },
106
94
  };
107
95
  }
108
96
 
109
97
  /**
110
98
  * Integración principal de astro-blog-kit.
111
- *
112
- * @example
113
- * ```js
114
- * // astro.config.mjs
115
- * import { defineConfig } from 'astro/config';
116
- * import { blogKit } from 'astro-blog-kit/integration';
117
- *
118
- * export default defineConfig({
119
- * integrations: [
120
- * blogKit({
121
- * postsPerPage: 6,
122
- * defaultLayout: 'featured',
123
- * theme: {
124
- * accent: '#facc15',
125
- * fontHeading: 'Inter, sans-serif',
126
- * },
127
- * }),
128
- * ],
129
- * });
130
- * ```
131
99
  */
132
100
  export function blogKit(config: BlogKitConfig = {}): AstroIntegration {
133
101
  const resolvedConfig: Required<BlogKitConfig> = {
134
- postsPerPage: config.postsPerPage ?? 5,
135
- defaultLayout: config.defaultLayout ?? "magazine",
102
+ postsPerPage: config.postsPerPage ?? 5,
103
+ defaultLayout: config.defaultLayout ?? "magazine",
136
104
  collectionName: config.collectionName ?? "blog",
137
- i18n: config.i18n ?? { locales: [], defaultLocale: "en" },
138
- theme: config.theme ?? {},
139
- hero: config.hero ?? {}, // ← agregar
140
- ui: config.ui ?? {},
105
+ i18n: config.i18n ?? { locales: [], defaultLocale: "en" },
106
+ theme: config.theme ?? {},
107
+ hero: config.hero ?? {},
108
+ ui: config.ui ?? {},
141
109
  };
142
110
 
143
111
  return {
@@ -149,20 +117,15 @@ export function blogKit(config: BlogKitConfig = {}): AstroIntegration {
149
117
  `astro-blog-kit initialized — layout: ${resolvedConfig.defaultLayout}, postsPerPage: ${resolvedConfig.postsPerPage}`
150
118
  );
151
119
 
152
- // Registra el virtual module como plugin de Vite
153
- // Esto garantiza que las CSS variables existen en SSR y en el build estático
120
+ // Pasa tanto theme como ui al plugin
154
121
  updateConfig({
155
122
  vite: {
156
- plugins: [createThemePlugin(resolvedConfig.theme)],
123
+ plugins: [createThemePlugin(resolvedConfig.theme, resolvedConfig.ui)],
157
124
  },
158
125
  });
159
126
 
160
- // Inyecta el virtual module en cada página como CSS real
161
- // "page-ssr" = se ejecuta en el servidor, garantiza que el style
162
- // esté disponible antes del primer paint
163
- injectScript("page-ssr", `import "${VIRTUAL_MODULE_ID}";`);
127
+ injectScript("page-ssr", `import "astro-blog-kit-theme.css";`);
164
128
 
165
- // Inyecta config global accesible desde cualquier componente
166
129
  injectScript(
167
130
  "page-ssr",
168
131
  `globalThis.__BLOG_KIT_CONFIG__ = ${JSON.stringify(resolvedConfig)};`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro-blog-kit",
3
- "version": "0.3.5",
3
+ "version": "0.3.7",
4
4
  "description": "A ready-to-use blog system for Astro with WordPress headless support, optional i18n, multiple layouts, and a comment system.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/types.ts CHANGED
@@ -2,32 +2,17 @@
2
2
  // astro-blog-kit · types.ts
3
3
  // ─────────────────────────────────────────────────────────────
4
4
 
5
- // ── Post ──────────────────────────────────────────────────────
6
-
7
5
  export interface BlogPost {
8
6
  id?: number;
9
7
  slug: string;
10
8
  date: string;
11
9
  modified?: string;
12
- title: {
13
- rendered: string;
14
- };
15
- excerpt: {
16
- rendered: string;
17
- };
18
- content: {
19
- rendered: string;
20
- };
10
+ title: { rendered: string };
11
+ excerpt: { rendered: string };
12
+ content: { rendered: string };
21
13
  _embedded?: {
22
- "wp:featuredmedia"?: Array<{
23
- source_url: string;
24
- alt_text?: string;
25
- }>;
26
- "wp:term"?: {
27
- id: number;
28
- name: string;
29
- slug: string;
30
- }[][];
14
+ "wp:featuredmedia"?: Array<{ source_url: string; alt_text?: string }>;
15
+ "wp:term"?: { id: number; name: string; slug: string }[][];
31
16
  };
32
17
  heroImage?: string;
33
18
  lang?: string;
@@ -35,12 +20,8 @@ export interface BlogPost {
35
20
  readingTime?: number;
36
21
  }
37
22
 
38
- // ── Layouts ───────────────────────────────────────────────────
39
-
40
23
  export type BlogListLayout = "grid" | "magazine" | "featured" | "cards";
41
24
 
42
- // ── i18n ──────────────────────────────────────────────────────
43
-
44
25
  export interface I18nConfig {
45
26
  locales: string[];
46
27
  defaultLocale: string;
@@ -58,8 +39,6 @@ export interface BlogTranslations {
58
39
  };
59
40
  }
60
41
 
61
- // ── Paginación ────────────────────────────────────────────────
62
-
63
42
  export interface PaginationProps {
64
43
  currentPage: number;
65
44
  totalPages: number;
@@ -68,8 +47,6 @@ export interface PaginationProps {
68
47
  t: BlogTranslations;
69
48
  }
70
49
 
71
- // ── BlogList ──────────────────────────────────────────────────
72
-
73
50
  export interface BlogListProps {
74
51
  posts: BlogPost[];
75
52
  currentPage: number;
@@ -79,66 +56,39 @@ export interface BlogListProps {
79
56
  dateLocale: string;
80
57
  t: BlogTranslations;
81
58
  locale: string;
82
- /** @default "magazine" */
83
59
  layout?: BlogListLayout;
84
60
  }
85
61
 
86
- // ── BlogPost componente ───────────────────────────────────────
87
-
88
62
  export interface BlogPostProps {
89
63
  post: BlogPost;
90
64
  t: BlogTranslations;
91
65
  lang: string;
92
66
  }
93
67
 
94
- // ── Tema ──────────────────────────────────────────────────────
95
-
96
68
  export interface BlogTheme {
97
- /** Color de acento principal. @default "#facc15" */
98
69
  accent?: string;
99
- /** Color de fondo. @default "#ffffff" */
100
70
  background?: string;
101
- /** Color de superficie (cards, sidebars). @default "#f8f8f8" */
102
71
  surface?: string;
103
- /** Color de texto principal. @default "#0a0a0a" */
104
72
  text?: string;
105
- /** Color de texto secundario. @default "#6b7280" */
106
73
  muted?: string;
107
- /** Color de texto secundario claro. @default "#9ca3af" */
108
74
  mutedLight?: string;
109
- /** Color de bordes. @default "#e5e7eb" */
110
75
  border?: string;
111
- /** Color negro para layouts. @default "#0a0a0a" */
112
76
  black?: string;
113
- /** Color blanco para layouts. @default "#ffffff" */
114
77
  white?: string;
115
- /** Fuente de títulos. @default "Georgia, serif" */
116
78
  fontHeading?: string;
117
- /** Fuente de cuerpo. @default "system-ui, sans-serif" */
118
79
  fontBody?: string;
119
- /** Fuente monospace. @default "monospace" */
120
80
  fontMono?: string;
121
- /** Fuente display (títulos grandes). @default "Georgia, serif" */
122
81
  fontDisplay?: string;
123
- /** Ancho máximo del contenedor. @default "1200px" */
124
82
  containerMax?: string;
125
83
  }
126
84
 
127
- // ── Hero del blog ─────────────────────────────────────────────
128
-
129
85
  export interface BlogHero {
130
- /** Texto del badge superior. @default "Our Blog" */
131
86
  tagline?: string;
132
- /** Primera línea del título. @default "Latest" */
133
87
  titleLine1?: string;
134
- /** Segunda línea del título (resaltada). @default "Articles" */
135
88
  titleLine2?: string;
136
- /** Párrafo descriptivo debajo del título. @default "Welcome to our blog." */
137
89
  description?: string;
138
90
  }
139
91
 
140
- // ── UI overrides ──────────────────────────────────────────────
141
-
142
92
  export interface BlogUI {
143
93
  /** Texto del botón "leer más". @default "Read more →" */
144
94
  readMoreLabel?: string;
@@ -152,35 +102,33 @@ export interface BlogUI {
152
102
  commentButtonTextColor?: string;
153
103
  /** Estilo de paginación. @default "minimal" */
154
104
  paginationStyle?: "minimal" | "numbered";
105
+ /** Fondo botones PREV/NEXT. @default accent */
106
+ paginationBtnBg?: string;
107
+ /** Texto botones PREV/NEXT. @default black */
108
+ paginationBtnText?: string;
109
+ /** Fondo botones PREV/NEXT en hover. @default text */
110
+ paginationBtnHoverBg?: string;
111
+ /** Texto botones PREV/NEXT en hover. @default white */
112
+ paginationBtnHoverText?: string;
113
+ /** Fondo página activa. @default accent */
114
+ paginationActiveBg?: string;
115
+ /** Texto página activa. @default black */
116
+ paginationActiveText?: string;
155
117
  }
156
118
 
157
- // ── Config del paquete ────────────────────────────────────────
158
-
159
119
  export interface BlogKitConfig {
160
- /** @default 5 */
161
120
  postsPerPage?: number;
162
121
  i18n?: I18nConfig;
163
- /** @default "magazine" */
164
122
  defaultLayout?: BlogListLayout;
165
- /** @default "blog" */
166
123
  collectionName?: string;
167
- /** Tema visual del blog */
168
124
  theme?: BlogTheme;
169
- /** Textos del hero/header del blog */
170
125
  hero?: BlogHero;
171
- /** Overrides de UI (botones, paginación, labels) */
172
126
  ui?: BlogUI;
173
127
  }
174
128
 
175
- // ── getStaticPaths ────────────────────────────────────────────
176
-
177
129
  export interface PageStaticPath {
178
130
  params: { page: string };
179
- props: {
180
- posts: BlogPost[];
181
- currentPage: number;
182
- totalPages: number;
183
- };
131
+ props: { posts: BlogPost[]; currentPage: number; totalPages: number };
184
132
  }
185
133
 
186
134
  export interface PostStaticPath {