@press2ai/theme-specialist-glossy 3.0.2 → 3.1.0

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@press2ai/theme-specialist-glossy",
3
- "version": "3.0.2",
3
+ "version": "3.1.0",
4
4
  "description": "Classless, AI-first glossy theme. Framework-agnostic templates (Hono, Astro, raw HTML). Semantic HTML, Schema.org microdata, JSON-LD — built for LLM crawlers.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/ai.ts CHANGED
@@ -59,7 +59,7 @@ export function getAiManifest(opts: {
59
59
 
60
60
  powered_by: {
61
61
  name: '@press2ai/theme-specialist-glossy',
62
- version: '3.0.2',
62
+ version: '3.1.0',
63
63
  homepage: 'https://www.npmjs.com/package/@press2ai/theme-specialist-glossy',
64
64
  },
65
65
 
@@ -1,16 +1,15 @@
1
1
  import { esc } from './helpers.ts';
2
2
 
3
- // Selector matches `<section>` whose direct child is the article cards rendered
4
- // by `profileCard()`. Cards themselves are styled by profile-card.ts using the
5
- // same selector head the two files share this invariant.
6
- const R = 'main > section:has(> article[itemscope])';
3
+ // Section identified by schema.org ItemList. profile-card.ts targets nested
4
+ // Person articles via the same ItemList head keep both in sync.
5
+ const R = 'main > section[itemtype$="ItemList"]';
7
6
 
8
7
  export const css = `${R} { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: var(--g3); }
9
8
  ${R} > h2 { grid-column: 1 / -1; }
10
9
  @media (max-width: 640px) { ${R} { grid-template-columns: 1fr; } }`;
11
10
 
12
- export function catalogGrid(p: { title: string; filters?: string; cards: string }): string {
13
- return `<section>
11
+ export function catalogGrid(p: { title: string; filters?: string; cards: string; ariaLabel?: string }): string {
12
+ return `<section itemscope itemtype="https://schema.org/ItemList" aria-label="${esc(p.ariaLabel ?? p.title)}">
14
13
  <h2>${esc(p.title)}</h2>
15
14
  ${p.filters ?? ''}
16
15
  ${p.cards}
@@ -1,9 +1,7 @@
1
1
  import { esc } from './helpers.ts';
2
2
 
3
- // Selector matches `<nav>` direct child of `main` that contains `<a>` — i.e.
4
- // the bare list-of-anchors nav rendered below. Hero's CTA <nav> sits inside
5
- // <hgroup>, not <main>, so it is not affected.
6
- const R = 'main > nav:has(> a)';
3
+ // Identified by schema.org SiteNavigationElement.
4
+ const R = 'main > nav[itemtype$="SiteNavigationElement"]';
7
5
 
8
6
  export const css = `${R} { display: flex; flex-wrap: wrap; gap: var(--g1); }
9
7
  ${R} > a {
@@ -16,5 +14,5 @@ ${R} > a:hover { border-color: var(--accent); color: var(--accent); background:
16
14
  export function categoryNav(items: { href: string; label: string }[], ariaLabel = 'Kategorie'): string {
17
15
  if (!items.length) return '';
18
16
  const links = items.map(i => `<a href="${esc(i.href)}">${esc(i.label)}</a>`).join('');
19
- return `<nav aria-label="${esc(ariaLabel)}">${links}</nav>`;
17
+ return `<nav itemscope itemtype="https://schema.org/SiteNavigationElement" aria-label="${esc(ariaLabel)}">${links}</nav>`;
20
18
  }
@@ -50,7 +50,7 @@ export interface LayoutProps {
50
50
  footerContent?: string;
51
51
  }
52
52
 
53
- const THEME_VERSION = '3.0.2';
53
+ const THEME_VERSION = '3.1.0';
54
54
 
55
55
  export function layout(props: LayoutProps, body: string): string {
56
56
  const {
@@ -1,8 +1,7 @@
1
1
  import { esc } from './helpers.ts';
2
2
 
3
- // Selector matches `<nav>` containing `<p>` the shape of `pagination()`.
4
- // category-nav uses `<nav>` containing `<a>` directly, not `<p>`, so they don't collide.
5
- const R = 'main > nav:has(> p)';
3
+ // Identified by data-section="pagination"schema.org has no pagination type.
4
+ const R = 'main > nav[data-section="pagination"]';
6
5
 
7
6
  export const css = `${R} > p { display: flex; align-items: center; justify-content: center; gap: var(--g3); font-size: 1rem; color: var(--fg-faint); }
8
7
  ${R} a {
@@ -27,5 +26,5 @@ export function pagination(p: PaginationProps): string {
27
26
  const extra = p.extraParams ?? '';
28
27
  const prev = p.current > 1 ? `<a href="${esc(base)}?p=${p.current - 1}${extra}">${esc(p.prevLabel ?? '\u2190 Poprzednia')}</a>` : '';
29
28
  const next = p.current < p.total ? `<a href="${esc(base)}?p=${p.current + 1}${extra}">${esc(p.nextLabel ?? 'Następna \u2192')}</a>` : '';
30
- return `<nav><p>${prev} Strona ${p.current} z ${p.total} ${next}</p></nav>`;
29
+ return `<nav data-section="pagination" aria-label="Paginacja"><p>${prev} Strona ${p.current} z ${p.total} ${next}</p></nav>`;
31
30
  }
@@ -1,9 +1,8 @@
1
1
  import type { Profile } from '../schema.ts';
2
2
  import { esc, fullName } from './helpers.ts';
3
3
 
4
- // Selector root MUST match the outer element below (`<article itemscope>` inside <main>).
5
- // If you change the HTML root, change R and vice versa. Keep them in this file together.
6
- const R = 'main > article[itemscope]';
4
+ // Selector is the schema.org Person fingerprint — must match the outer element below.
5
+ const R = 'main > article[itemtype$="Person"]';
7
6
 
8
7
  export const css = `${R} { max-width: 667px; }
9
8
  ${R} > header { padding-bottom: var(--g4); margin-bottom: var(--g4); border-bottom: 2px solid var(--fg); }
@@ -1,10 +1,8 @@
1
1
  import type { Profile } from '../schema.ts';
2
2
  import { esc, fullName } from './helpers.ts';
3
3
 
4
- // Card sits inside catalog grid: `<section><h2>...</h2><article>...</article>...</section>`.
5
- // Selector targets the article only when wrapped by such a section keep that
6
- // shape in sync with `catalogGrid()` in catalog-grid.ts.
7
- const R = 'main > section:has(> article[itemscope]) > article[itemscope]';
4
+ // Card = Person inside ItemList rendered by catalogGrid(). Keep in sync.
5
+ const R = 'main > section[itemtype$="ItemList"] > article[itemtype$="Person"]';
8
6
 
9
7
  export const css = `${R} {
10
8
  background: var(--card); border: 1px solid var(--border); border-radius: var(--r-lg);
@@ -40,7 +38,7 @@ export function profileCard(p: Profile, href: string): string {
40
38
  ? `<ul>${p.specialties.slice(0, 3).map(s => `<li>${esc(s)}</li>`).join('')}</ul>`
41
39
  : '';
42
40
 
43
- return `<article itemscope itemtype="https://schema.org/Person">
41
+ return `<article itemprop="itemListElement" itemscope itemtype="https://schema.org/Person">
44
42
  <div aria-hidden="true">${initials}</div>
45
43
  <header>
46
44
  <h2><a href="${esc(href)}" itemprop="url"><span itemprop="name">${esc(name)}</span></a></h2>
@@ -1,8 +1,7 @@
1
1
  import { esc } from './helpers.ts';
2
2
 
3
- // Selector matches `<section>` whose direct child is `<dl>` that's how
4
- // `statBar()` below renders. If you change the wrapper, update the selector.
5
- const R = 'main > section:has(> dl)';
3
+ // Identified by data-section="stats" no good schema.org type for stats.
4
+ const R = 'main > section[data-section="stats"]';
6
5
 
7
6
  export const css = `${R} > dl { display: flex; justify-content: center; gap: var(--g5); }
8
7
  ${R} > dl div { text-align: center; }
@@ -27,5 +26,5 @@ export function statBar(items: { value: string; label: string; icon?: string }[]
27
26
  return `<div>${icon}<dt>${esc(i.value)}</dt><dd>${esc(i.label)}</dd></div>`;
28
27
  }).join('\n');
29
28
  const summaryP = summary ? `<p>${esc(summary)}</p>` : '';
30
- return `<section aria-label="Statystyki">${summaryP}<dl aria-hidden="true">\n${divs}\n</dl></section>`;
29
+ return `<section data-section="stats" role="region" aria-label="Statystyki">${summaryP}<dl aria-hidden="true">\n${divs}\n</dl></section>`;
31
30
  }
@@ -1,7 +1,7 @@
1
1
  import { esc, BREAKOUT } from './helpers.ts';
2
2
 
3
- // Selector matches `<section>` containing `<ol>` — that's the shape of `steps()` below.
4
- const R = 'main > section:has(> ol)';
3
+ // Identified by schema.org HowTo.
4
+ const R = 'main > section[itemtype$="HowTo"]';
5
5
 
6
6
  export const css = `${R} {
7
7
  ${BREAKOUT} background: var(--surface); padding-block: var(--g5);
@@ -27,6 +27,6 @@ ${R} > ol > li span { font-size: .8rem; line-height: 1.5; color: var(--fg-faint)
27
27
  @media (max-width: 640px) { ${R} > ol { grid-template-columns: 1fr; } }`;
28
28
 
29
29
  export function steps(title: string, items: { title: string; description: string }[]): string {
30
- const lis = items.map(i => `<li><strong>${esc(i.title)}</strong><span>${esc(i.description)}</span></li>`).join('\n');
31
- return `<section>\n<h2>${esc(title)}</h2>\n<ol>\n${lis}\n</ol>\n</section>`;
30
+ const lis = items.map(i => `<li itemprop="step" itemscope itemtype="https://schema.org/HowToStep"><strong itemprop="name">${esc(i.title)}</strong><span itemprop="text">${esc(i.description)}</span></li>`).join('\n');
31
+ return `<section itemscope itemtype="https://schema.org/HowTo">\n<h2 itemprop="name">${esc(title)}</h2>\n<ol>\n${lis}\n</ol>\n</section>`;
32
32
  }