keystone-design-bootstrap 1.0.11 → 1.0.12

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/README.md CHANGED
@@ -3,8 +3,9 @@
3
3
  A comprehensive design system for Keystone customer websites. Provides themed sections, elements, and utilities for building consistent, server-rendered Next.js sites.
4
4
 
5
5
  **Rules:**
6
+ - Theme variants MUST use identical props interface as base component (e.g., if base uses `title`, variant must use `title`, not `headline`)
6
7
  - Use CSS variables only (no hardcoded colors/fonts in components)
7
- - Reference `next/font` variables in CSS with fallbacks
8
+ - Add theme fonts to customer template's `globals.css` (see below)
8
9
  - Use semantic classes (`bg-primary`, `text-fg-primary`, `font-display`)
9
10
  - Keep CSS overrides minimal (~100 lines max)
10
11
  - Mirror color variables to both `--color-*` and `--background-*` prefixes
@@ -121,13 +122,24 @@ export const THEME_CONFIG = {
121
122
  } as const;
122
123
  ```
123
124
 
124
- ### 2. Create CSS Overrides
125
+ ### 2. Add Fonts to Customer Template
126
+ In customer template's `app/globals.css`, add font imports after `@import "tailwindcss"`:
127
+ ```css
128
+ @import "tailwindcss";
129
+
130
+ /* Add your theme fonts here */
131
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600&family=Playfair+Display:wght@400;700&display=swap');
132
+
133
+ /* Rest of file... */
134
+ ```
135
+
136
+ ### 3. Create CSS Overrides
125
137
  `src/styles/style-overrides.mytheme.css`:
126
138
  ```css
127
139
  [data-theme="mytheme"] {
128
140
  /* Typography */
129
- --font-body: var(--font-inter), "Inter", sans-serif;
130
- --font-display: var(--font-playfair), "Playfair Display", serif;
141
+ --font-body: "Inter", sans-serif;
142
+ --font-display: "Playfair Display", serif;
131
143
 
132
144
  /* Colors - set both prefixes */
133
145
  --color-bg-primary: #FFFFFF;
@@ -146,24 +158,39 @@ export const THEME_CONFIG = {
146
158
  }
147
159
  ```
148
160
 
149
- ### 3. Load Fonts
150
- In customer template's `app/layout.tsx`:
161
+ ### 4. Test Theme
162
+ Set in customer site's `config/index.ts`:
151
163
  ```typescript
152
- import { Inter, Playfair_Display } from "next/font/google";
164
+ export const config: SiteConfig = {
165
+ site: {
166
+ theme: "mytheme"
167
+ }
168
+ }
169
+ ```
170
+
171
+ **Note:** Fonts are loaded in `globals.css` for all themes. While this means all theme fonts load upfront, it's simpler than dynamic loading and fonts are cached anyway. For ~5-10 themes this is acceptable overhead.
153
172
 
154
- const inter = Inter({ variable: "--font-inter", subsets: ["latin"] });
155
- const playfair = Playfair_Display({ variable: "--font-playfair", subsets: ["latin"] });
173
+ ### 5. Create Component Variants (Optional)
174
+ Use the exact same props interface as the base component (otherwise switching between themes will break).
156
175
 
157
- <body className={`${inter.variable} ${playfair.variable}`}>
176
+ Check the base component first:
177
+ ```typescript
178
+ // Check: src/design_system/sections/hero-home.tsx
179
+ interface HeroHomeProps {
180
+ headline?: string; // ← Use these prop names
181
+ subhead?: string;
182
+ // ...
183
+ }
158
184
  ```
159
185
 
160
- ### 4. Create Component Variants (optional)
161
- `src/design_system/sections/hero-home.mytheme.tsx`:
186
+ Then create variant with matching interface:
162
187
  ```typescript
163
- export const HeroHome = (props) => (
188
+ // src/design_system/sections/hero-home.mytheme.tsx
189
+ export const HeroHome = ({ headline, subhead, ctaText, ctaHref }: HeroHomeProps) => (
164
190
  <section className="bg-primary py-20">
165
- <h1 className="font-display text-display-xl">{props.headline}</h1>
166
- <Button color="primary" size="md">{props.ctaText}</Button>
191
+ <h1 className="font-display text-display-xl">{headline}</h1>
192
+ <p className="font-body text-lg">{subhead}</p>
193
+ <Button href={ctaHref} color="primary" size="md">{ctaText}</Button>
167
194
  </section>
168
195
  );
169
196
 
@@ -171,16 +198,8 @@ import { registerThemeVariant } from '../../lib/component-registry';
171
198
  registerThemeVariant('hero-home', 'mytheme', HeroHome);
172
199
  ```
173
200
 
174
- ### 5. Register Variants
201
+ ### 6. Register Component Variants
175
202
  `src/design_system/sections/index.tsx`:
176
203
  ```typescript
177
204
  import './hero-home.mytheme';
178
205
  ```
179
-
180
- ### 6. Use Theme
181
- Customer site's `config/index.ts`:
182
- ```typescript
183
- export const config = {
184
- site: { theme: "mytheme" }
185
- }
186
- ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "keystone-design-bootstrap",
3
- "version": "1.0.11",
3
+ "version": "1.0.12",
4
4
  "description": "Keystone Design Bootstrap - Sections, Elements, and Theme System for customer websites",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -4,6 +4,7 @@ import { Button } from '../elements';
4
4
  import { FeatureTextFeaturedIconCard } from './feature-text';
5
5
  import { mapIcon } from '../utils/icon-mapping';
6
6
  import type { CompanyInformation } from '../../types/api/company-information';
7
+ import type { WebsitePhotos } from '../../types/api/website-photos';
7
8
 
8
9
  interface Value {
9
10
  id?: string;
@@ -15,6 +16,7 @@ interface Value {
15
16
 
16
17
  interface AboutHomeProps {
17
18
  companyInformation?: CompanyInformation | null;
19
+ websitePhotos?: WebsitePhotos | null;
18
20
  title?: string;
19
21
  subtitle?: string;
20
22
  values?: Value[];
@@ -24,6 +26,7 @@ interface AboutHomeProps {
24
26
 
25
27
  export const AboutHome = ({
26
28
  companyInformation,
29
+ websitePhotos,
27
30
  title = "",
28
31
  subtitle = "",
29
32
  values = [],
@@ -5,15 +5,15 @@ import { ChevronLeft, ChevronRight } from '@untitledui/icons';
5
5
 
6
6
  interface BlogSectionProps {
7
7
  blogPosts?: BlogPost[] | null;
8
- headline?: string;
9
- subhead?: string;
8
+ title?: string;
9
+ subtitle?: string;
10
10
  maxPosts?: number;
11
11
  }
12
12
 
13
13
  export const BlogSection = ({
14
14
  blogPosts: postsData,
15
- headline = "*TR* Latest from Our Blog",
16
- subhead = "*TR* Stay updated with our latest news, tips, and insights.",
15
+ title = "*TR* Latest from Our Blog",
16
+ subtitle = "*TR* Stay updated with our latest news, tips, and insights.",
17
17
  maxPosts,
18
18
  }: BlogSectionProps) => {
19
19
 
@@ -38,10 +38,10 @@ export const BlogSection = ({
38
38
  {/* Section Header - Centered */}
39
39
  <div className="mx-auto max-w-3xl text-center mb-12 md:mb-16">
40
40
  <h2 className="font-display text-4xl font-medium text-fg-primary md:text-5xl mb-4">
41
- {headline}
41
+ {title}
42
42
  </h2>
43
43
  <p className="font-body text-lg text-secondary leading-normal">
44
- {subhead}
44
+ {subtitle}
45
45
  </p>
46
46
  </div>
47
47
 
@@ -53,11 +53,6 @@ export function HeaderNavigation({
53
53
  const handleMouseEnter = useCallback((item: NavItem, e: React.MouseEvent<HTMLDivElement>) => {
54
54
  cancelCloseTimeout();
55
55
  if (item.children && item.children.length > 0) {
56
- const target = e.currentTarget.closest('nav');
57
- if (target) {
58
- const rect = target.getBoundingClientRect();
59
- setDropdownTop(rect.bottom);
60
- }
61
56
  setActiveDropdown(item.label);
62
57
  }
63
58
  }, [cancelCloseTimeout]);
@@ -4,14 +4,14 @@ import type { Service } from '../../types/api/service';
4
4
 
5
5
  interface ServicesHomeProps {
6
6
  services: Service[];
7
- headline?: string;
8
- subhead?: string;
7
+ title?: string;
8
+ subtitle?: string;
9
9
  }
10
10
 
11
11
  export const ServicesHome = ({
12
12
  services = [],
13
- headline = "*TR* Explore Our Signature Services",
14
- subhead = "*TR* Discover our comprehensive menu of expertly curated, non-invasive treatments. Each service is designed to help you achieve your aesthetic goals, enhance your natural beauty, and boost your confidence.",
13
+ title = "*TR* Explore Our Signature Services",
14
+ subtitle = "*TR* Discover our comprehensive menu of expertly curated, non-invasive treatments. Each service is designed to help you achieve your aesthetic goals, enhance your natural beauty, and boost your confidence.",
15
15
  }: ServicesHomeProps) => {
16
16
  // Show all services
17
17
  const displayServices = services;
@@ -22,10 +22,10 @@ export const ServicesHome = ({
22
22
  {/* Section Header - Centered */}
23
23
  <div className="mx-auto max-w-3xl text-center mb-12">
24
24
  <h2 className="font-display text-display-md font-normal text-fg-primary mb-4">
25
- {headline}
25
+ {title}
26
26
  </h2>
27
27
  <p className="font-body text-base text-secondary leading-normal">
28
- {subhead}
28
+ {subtitle}
29
29
  </p>
30
30
  </div>
31
31
 
@@ -6,14 +6,14 @@ import { ChevronLeft, ChevronRight } from '@untitledui/icons';
6
6
 
7
7
  interface TestimonialsHomeProps {
8
8
  testimonials?: Testimonial[] | null;
9
- headline?: string;
10
- subhead?: string;
9
+ title?: string;
10
+ subtitle?: string;
11
11
  }
12
12
 
13
13
  export const TestimonialsHome = ({
14
14
  testimonials: testimonialsData,
15
- headline = "*TR* What Our Clients Say",
16
- subhead = "*TR* Discover the transformative experiences of our clients. Read their testimonials to hear firsthand about their journeys to enhanced natural beauty, renewed confidence, and the exceptional care they received at Bare Lux Studio.",
15
+ title = "*TR* What Our Clients Say",
16
+ subtitle = "*TR* Discover the transformative experiences of our clients. Read their testimonials to hear firsthand about their journeys to enhanced natural beauty, renewed confidence, and the exceptional care they received at Bare Lux Studio.",
17
17
  }: TestimonialsHomeProps) => {
18
18
  const testimonials = Array.isArray(testimonialsData) ? testimonialsData : [];
19
19
 
@@ -23,10 +23,10 @@ export const TestimonialsHome = ({
23
23
  {/* Section Header - Centered */}
24
24
  <div className="mx-auto max-w-3xl text-center mb-12 md:mb-16">
25
25
  <h2 className="font-display text-4xl font-medium text-fg-primary md:text-5xl mb-4">
26
- {headline}
26
+ {title}
27
27
  </h2>
28
28
  <p className="font-body text-lg text-secondary leading-normal">
29
- {subhead}
29
+ {subtitle}
30
30
  </p>
31
31
  </div>
32
32
 
@@ -1,10 +1,9 @@
1
1
  /* Aman Theme Overrides */
2
2
 
3
- /* Aman theme typography and colors */
4
3
  [data-theme="aman"] {
5
- /* Typography - use actual font names since CSS variables from next/font are scoped to body */
6
- --font-body: "Inter", "Inter Fallback", -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
7
- --font-display: "Playfair Display", "Playfair Display Fallback", "Didot", "Georgia", serif;
4
+ /* Typography */
5
+ --font-body: "Inter", -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
6
+ --font-display: "Playfair Display", "Didot", "Georgia", serif;
8
7
 
9
8
  /* Aman color palette - warm, elegant tones */
10
9
  --color-bg-primary: #F9F7F0; /* Light warm beige */
@@ -1,10 +1,9 @@
1
1
  /* Bare Lux Studio Theme Overrides */
2
2
 
3
- /* Bare Lux theme typography and colors */
4
3
  [data-theme="barelux"] {
5
4
  /* Typography - Merriweather for headings, Poppins for body */
6
- --font-body: var(--font-poppins), "Poppins", -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
7
- --font-display: var(--font-merriweather), "Merriweather", "Georgia", serif;
5
+ --font-body: "Poppins", -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
6
+ --font-display: "Merriweather", "Georgia", serif;
8
7
 
9
8
  /* Bare Lux color palette - soft peachy rose aesthetic */
10
9
  --color-bg-primary: #FDFCFB;
@@ -45,7 +44,7 @@
45
44
 
46
45
  /* Body text uses Poppins */
47
46
  [data-theme="barelux"] body {
48
- font-family: var(--font-poppins), "Poppins", -apple-system, "Segoe UI", Roboto, Arial, sans-serif !important;
47
+ font-family: "Poppins", -apple-system, "Segoe UI", Roboto, Arial, sans-serif !important;
49
48
  background-color: #FDFCFB;
50
49
  }
51
50
 
@@ -56,19 +55,19 @@
56
55
  [data-theme="barelux"] h4,
57
56
  [data-theme="barelux"] h5,
58
57
  [data-theme="barelux"] h6 {
59
- font-family: var(--font-merriweather), "Merriweather", "Georgia", serif !important;
58
+ font-family: "Merriweather", "Georgia", serif !important;
60
59
  font-weight: 400;
61
60
  }
62
61
 
63
62
  /* .font-display class uses Merriweather */
64
63
  [data-theme="barelux"] .font-display {
65
- font-family: var(--font-merriweather), "Merriweather", "Georgia", serif !important;
64
+ font-family: "Merriweather", "Georgia", serif !important;
66
65
  font-weight: 400;
67
66
  }
68
67
 
69
68
  /* .font-body class uses Poppins */
70
69
  [data-theme="barelux"] .font-body {
71
- font-family: var(--font-poppins), "Poppins", -apple-system, "Segoe UI", Roboto, Arial, sans-serif !important;
70
+ font-family: "Poppins", -apple-system, "Segoe UI", Roboto, Arial, sans-serif !important;
72
71
  }
73
72
 
74
73
  /* Fix header background */
@@ -84,13 +83,14 @@
84
83
 
85
84
  /* Navigation styling */
86
85
  [data-theme="barelux"] nav {
87
- font-family: var(--font-poppins), "Poppins", -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
86
+ font-family: "Poppins", -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
87
+ font-weight: 600;
88
88
  }
89
89
 
90
90
  /* Button text */
91
91
  [data-theme="barelux"] button,
92
92
  [data-theme="barelux"] .btn {
93
- font-family: var(--font-poppins), "Poppins", -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
93
+ font-family: "Poppins", -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
94
94
  }
95
95
 
96
96
  /* Sections background */