@chronogrove/ui 0.83.3 → 0.84.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chronogrove/ui",
3
- "version": "0.83.3",
3
+ "version": "0.84.1",
4
4
  "description": "Chronogrove Theme UI theme, color mode helpers, and shared UI primitives",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -142,6 +142,10 @@
142
142
  "import": "./src/article-column-container.js",
143
143
  "default": "./src/article-column-container.js"
144
144
  },
145
+ "./category-index-layout": {
146
+ "import": "./src/category-index-layout.js",
147
+ "default": "./src/category-index-layout.js"
148
+ },
145
149
  "./home-dashboard-layout": {
146
150
  "import": "./src/home-dashboard-layout.js",
147
151
  "default": "./src/home-dashboard-layout.js"
@@ -61,7 +61,7 @@ const ActionButton = ({ children, href, onClick, variant = 'primary', size = 'me
61
61
  const content = (
62
62
  <>
63
63
  {children}
64
- {icon && icon}
64
+ {icon}
65
65
  </>
66
66
  )
67
67
 
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Shared layout for category-style index pages (blog, travel, music, etc.)
3
+ * under the animated hero background.
4
+ */
5
+
6
+ import React, { Fragment } from 'react'
7
+ import { Box } from '@theme-ui/components'
8
+
9
+ import AnimatedPageBackground from './animated-page-background/index.js'
10
+
11
+ /** Outer column flex (below site chrome): stacks header + content with consistent vertical rhythm. */
12
+ export const categoryIndexMainColumnFlexSx = {
13
+ flexDirection: 'column',
14
+ flexGrow: 1,
15
+ position: 'relative',
16
+ py: 3
17
+ }
18
+
19
+ /** `sx` for the post list `<section>` (matches Travel index spacing). */
20
+ export const categoryIndexPostListSectionSx = {
21
+ display: 'grid',
22
+ gridGap: [2, 2, 3, 3],
23
+ gridTemplateColumns: '1fr',
24
+ mt: 4
25
+ }
26
+
27
+ /** `sx` for the empty-state wrapper under the header. */
28
+ export const categoryIndexEmptyStateBoxSx = {
29
+ textAlign: 'center',
30
+ py: 6,
31
+ mt: 4
32
+ }
33
+
34
+ /**
35
+ * Animated gradient hero + elevated content layer (same stacking as Travel/Music/Blog indexes).
36
+ *
37
+ * @param {object} props
38
+ * @param {React.ReactNode} props.children
39
+ * @param {string} [props.overlayHeight]
40
+ */
41
+ export function CategoryIndexHeroChrome({ children, overlayHeight = 'min(75vh, 1000px)' }) {
42
+ return (
43
+ <Fragment>
44
+ <AnimatedPageBackground overlayHeight={overlayHeight} />
45
+ <Box
46
+ sx={{
47
+ position: 'relative',
48
+ zIndex: 1
49
+ }}
50
+ >
51
+ {children}
52
+ </Box>
53
+ </Fragment>
54
+ )
55
+ }
@@ -0,0 +1,71 @@
1
+ import React from 'react'
2
+ import { render, screen } from '@testing-library/react'
3
+ import '@testing-library/jest-dom'
4
+
5
+ import {
6
+ CategoryIndexHeroChrome,
7
+ categoryIndexEmptyStateBoxSx,
8
+ categoryIndexMainColumnFlexSx,
9
+ categoryIndexPostListSectionSx
10
+ } from './category-index-layout.js'
11
+
12
+ jest.mock('./animated-page-background/index.js', () => ({
13
+ __esModule: true,
14
+ default: ({ overlayHeight }) => <div data-testid='animated-page-background' data-overlay={overlayHeight} />
15
+ }))
16
+
17
+ describe('categoryIndexPostListSectionSx', () => {
18
+ it('matches shared index grid layout', () => {
19
+ expect(categoryIndexPostListSectionSx).toMatchObject({
20
+ display: 'grid',
21
+ gridGap: [2, 2, 3, 3],
22
+ gridTemplateColumns: '1fr',
23
+ mt: 4
24
+ })
25
+ })
26
+ })
27
+
28
+ describe('categoryIndexEmptyStateBoxSx', () => {
29
+ it('matches shared empty state spacing', () => {
30
+ expect(categoryIndexEmptyStateBoxSx).toMatchObject({
31
+ textAlign: 'center',
32
+ py: 6,
33
+ mt: 4
34
+ })
35
+ })
36
+ })
37
+
38
+ describe('categoryIndexMainColumnFlexSx', () => {
39
+ it('matches main column flex rhythm', () => {
40
+ expect(categoryIndexMainColumnFlexSx).toMatchObject({
41
+ flexDirection: 'column',
42
+ flexGrow: 1,
43
+ position: 'relative',
44
+ py: 3
45
+ })
46
+ })
47
+ })
48
+
49
+ describe('CategoryIndexHeroChrome', () => {
50
+ it('defaults overlay height when omitted', () => {
51
+ render(
52
+ <CategoryIndexHeroChrome>
53
+ <div data-testid='inner'>Hello</div>
54
+ </CategoryIndexHeroChrome>
55
+ )
56
+
57
+ expect(screen.getByTestId('animated-page-background')).toHaveAttribute('data-overlay', 'min(75vh, 1000px)')
58
+ expect(screen.getByTestId('inner')).toHaveTextContent('Hello')
59
+ })
60
+
61
+ it('renders animated background and stacks children above it', () => {
62
+ render(
63
+ <CategoryIndexHeroChrome overlayHeight='42vh'>
64
+ <div data-testid='inner'>Hello</div>
65
+ </CategoryIndexHeroChrome>
66
+ )
67
+
68
+ expect(screen.getByTestId('animated-page-background')).toHaveAttribute('data-overlay', '42vh')
69
+ expect(screen.getByTestId('inner')).toHaveTextContent('Hello')
70
+ })
71
+ })
@@ -92,7 +92,7 @@ const PaginationButton = ({
92
92
  const content = (
93
93
  <>
94
94
  {children}
95
- {icon && icon}
95
+ {icon}
96
96
  </>
97
97
  )
98
98