@kolkrabbi/kol-framework 0.60.0 → 0.61.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/kol-framework.css CHANGED
@@ -32,8 +32,15 @@ body {
32
32
  * law, brand-app ruling): text is selectable everywhere — copyability beats
33
33
  * chrome purity. */
34
34
 
35
- /* Selection highlight uses brand-primary so it reads on-brand when it appears. */
35
+ /* SELECTED TEXT IS NEUTRAL BY DEFAULT (ArticleRendererHomeHeroSelection, kol-website 2026-10-28 — user: accents are opt-in,
36
+ * not default; brand's selections were yellow): the page's own ink pair, inverted — a white highlight with dark ink in dark
37
+ * mode, its inverse in light. An app (or any subtree) opts into the accent with `.kol-select-accent`. */
36
38
  ::selection {
39
+ background-color: var(--kol-surface-on-primary);
40
+ color: var(--kol-surface-primary);
41
+ }
42
+ .kol-select-accent::selection,
43
+ .kol-select-accent ::selection {
37
44
  background-color: var(--kol-accent-primary);
38
45
  color: var(--kol-accent-on-primary);
39
46
  }
@@ -250,6 +257,20 @@ body {
250
257
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 3rem), transparent);
251
258
  mask-image: linear-gradient(to bottom, #000 calc(100% - 3rem), transparent);
252
259
  }
260
+ /* THE SITE HERO'S WASH (SiteHero, 2026-10-28) — kol-website's `.landing-hero-overlay` and `.stack-hero-overlay`, one rule:
261
+ * the inverse ink mixed over the image, 32 % light · 80 % dark, the theme law's selectors (explicit > system > light).
262
+ * SiteHero's `overlay` prop sets the two variables. */
263
+ .kol-site-hero-overlay {
264
+ background-color: color-mix(in srgb, var(--kol-surface-on-inverse, currentColor) var(--kol-site-hero-mix, 32%), transparent);
265
+ }
266
+ :is([data-theme="dark"], .dark) .kol-site-hero-overlay {
267
+ background-color: color-mix(in srgb, var(--kol-surface-on-inverse, currentColor) var(--kol-site-hero-mix-dark, 80%), transparent);
268
+ }
269
+ @media (prefers-color-scheme: dark) {
270
+ :root:not([data-theme="light"]) .kol-site-hero-overlay {
271
+ background-color: color-mix(in srgb, var(--kol-surface-on-inverse, currentColor) var(--kol-site-hero-mix-dark, 80%), transparent);
272
+ }
273
+ }
253
274
  .kol-sidenav-list {
254
275
  display: flex;
255
276
  flex-direction: column;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kolkrabbi/kol-framework",
3
- "version": "0.60.0",
3
+ "version": "0.61.0",
4
4
  "description": "Site shell and page layout",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -14,7 +14,7 @@
14
14
  "./kol-brand-color.css": "./kol-brand-color.css"
15
15
  },
16
16
  "peerDependencies": {
17
- "@kolkrabbi/kol-component": ">=0.298.0",
17
+ "@kolkrabbi/kol-component": ">=0.308.0",
18
18
  "@kolkrabbi/kol-icons": ">=0.18.0",
19
19
  "@kolkrabbi/kol-markdown": ">=0.2.0",
20
20
  "@kolkrabbi/kol-theme": ">=0.186.0",
@@ -23,9 +23,9 @@
23
23
  "react-router-dom": "^6.0.0 || ^7.0.0"
24
24
  },
25
25
  "devDependencies": {
26
- "@kolkrabbi/kol-markdown": "0.2.0",
27
- "@kolkrabbi/kol-component": "^0.308.0",
28
- "@kolkrabbi/kol-icons": "^0.50.0"
26
+ "@kolkrabbi/kol-component": "^0.310.0",
27
+ "@kolkrabbi/kol-icons": "^0.52.0",
28
+ "@kolkrabbi/kol-markdown": "0.2.0"
29
29
  },
30
30
  "files": [
31
31
  "src",
@@ -0,0 +1,64 @@
1
+ import { VectorLoader } from '@kolkrabbi/kol-component'
2
+
3
+ /**
4
+ * SiteHero — A site's landing: a full-screen image, a wash, the mark, the name. kol-website apps/brand's `Landing`, class
5
+ * for class (ArticleRendererHomeHeroSelection, kol-website 2026-10-28 — three hand-built copies: brand's Landing, record's
6
+ * Home, site-hub's Home; web's /stack hero wears the same wash). Every part is optional, so the next site needs no copy.
7
+ *
8
+ * Not `PageHero`: that is a page's opening band (label · title · lede beside a mark). This is the home page itself.
9
+ *
10
+ * @param {Object} image `{ src, srcSet?, sizes?, position?, alt? }` — the ground, `object-cover`, `sizes` 100vw by default
11
+ * @param {ReactNode} media any node in place of `image` (a video, a canvas), filling the ground
12
+ * @param {ReactNode|string} mark a node, or an SVG url inlined in currentColor (`VectorLoader`); the hero sizes it, the
13
+ * landing's clamp(140px, 16vw, 220px)
14
+ * @param {string} markTitle the mark's accessible name when it is a url
15
+ * @param {ReactNode} title the h1, `kol-prose-display uppercase`
16
+ * @param {ReactNode} tagline `kol-prose-tagline`
17
+ * @param {ReactNode} actions buttons under the tagline, wrapped and centred
18
+ * @param {number|{light,dark}|false} overlay the wash: the inverse ink mixed over the image, 32 % light · 80 % dark by
19
+ * default (the sites' line); a number sets both, `false` drops it
20
+ * @param {'center'|'start'} align the text column — centred (default) or from the left
21
+ * @param {string} minHeight default `100dvh`
22
+ */
23
+ export default function SiteHero({ image, media, mark, markTitle, title, tagline, actions, overlay, align = 'center', minHeight = '100dvh', className = '' }) {
24
+ const start = align === 'start'
25
+ const wash = overlay === false ? null
26
+ : typeof overlay === 'number' ? { '--kol-site-hero-mix': `${overlay}%`, '--kol-site-hero-mix-dark': `${overlay}%` }
27
+ : overlay && typeof overlay === 'object' ? { ...(overlay.light != null && { '--kol-site-hero-mix': `${overlay.light}%` }), ...(overlay.dark != null && { '--kol-site-hero-mix-dark': `${overlay.dark}%` }) }
28
+ : {}
29
+ return (
30
+ <section className={`relative flex items-center ${start ? 'justify-start' : 'justify-center'} overflow-hidden ${className}`.trim()} style={{ minHeight }}>
31
+ {(image || media) && (
32
+ <div className="absolute inset-0 w-full h-full">
33
+ {media ?? (
34
+ <img
35
+ src={image.src}
36
+ srcSet={image.srcSet}
37
+ sizes={image.srcSet ? (image.sizes ?? '100vw') : undefined}
38
+ alt={image.alt ?? ''}
39
+ className="w-full h-full object-cover"
40
+ style={{ objectPosition: image.position ?? 'center' }}
41
+ />
42
+ )}
43
+ </div>
44
+ )}
45
+ {wash && <div className="kol-site-hero-overlay absolute inset-0 w-full h-full pointer-events-none" style={wash} aria-hidden="true" />}
46
+
47
+ <div className={`relative z-[1] flex flex-col gap-10 px-8 ${start ? 'items-start text-left' : 'items-center text-center'}`}>
48
+ {mark && (
49
+ <div className="w-[clamp(140px,16vw,220px)] text-emphasis">
50
+ {typeof mark === 'string'
51
+ ? <VectorLoader src={mark} size="100%" className="block" role={markTitle ? 'img' : undefined} aria-label={markTitle} />
52
+ : mark}
53
+ </div>
54
+ )}
55
+
56
+ {title && <h1 className="kol-prose-display uppercase">{title}</h1>}
57
+
58
+ {tagline && <p className="kol-prose-tagline">{tagline}</p>}
59
+
60
+ {actions && <div className={`flex flex-wrap items-center gap-3 mt-4 ${start ? 'justify-start' : 'justify-center'}`}>{actions}</div>}
61
+ </div>
62
+ </section>
63
+ )
64
+ }
package/src/index.js CHANGED
@@ -26,6 +26,8 @@ export { default as PageSection } from './PageSection.jsx'
26
26
  export { default as PortalFooter } from './PortalFooter.jsx'
27
27
  export { default as ScrollToTop } from './ScrollToTop.jsx'
28
28
  export { default as PageHero, default as BrandHero, default as SubPageHero } from './PageHero.jsx'
29
+ /* a site's landing — the full-screen image, wash, mark and name (ArticleRendererHomeHeroSelection, 2026-10-28) */
30
+ export { default as SiteHero } from './SiteHero.jsx'
29
31
  export { default as CategoryPage } from './CategoryPage.jsx'
30
32
  /* the document page (plan-2026-10-28-document W5.2): a markdown file as `.kol-sheet`, the hover card for its links,
31
33
  * a folder of files as page rows */