keystone-design-bootstrap 1.0.74 → 1.0.75

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
@@ -102,6 +102,165 @@ yalc remove keystone-design-bootstrap && npm install
102
102
 
103
103
  ---
104
104
 
105
+ ## Custom sites (blank-slate)
106
+
107
+ The `custom` theme is for fully custom, agency-built sites that use this package **for data and routing only** — no design-system CSS, no inherited brand colors, no pre-styled components. The visual layer is built entirely within the site itself.
108
+
109
+ ### When to use `custom`
110
+
111
+ - The site is built by an agency with its own design language
112
+ - You want GSAP animations and custom layouts that don't map to any existing section/element
113
+ - You need full CSS control with no risk of design-system styles leaking through
114
+
115
+ ### Setup
116
+
117
+ #### 1. Config
118
+
119
+ ```typescript
120
+ // config/index.ts
121
+ export const config: SiteConfig = {
122
+ site: { title: "Site Name", description: "…", theme: "custom" },
123
+ navigation: { header: […], footer: [[…]] },
124
+ };
125
+ ```
126
+
127
+ #### 2. CSS — import nothing from this package
128
+
129
+ ```css
130
+ /* app/globals.css */
131
+ @import "tailwindcss";
132
+
133
+ /* Optional Tailwind plugins */
134
+ @plugin "@tailwindcss/typography";
135
+ @plugin "tailwindcss-react-aria-components";
136
+ @plugin "tailwindcss-animate";
137
+
138
+ /*
139
+ * Scan the design-bootstrap source so Tailwind doesn't purge classes used
140
+ * by any data-layer components that get rendered at runtime.
141
+ */
142
+ @source "../node_modules/keystone-design-bootstrap/src/**/*.{ts,tsx}";
143
+
144
+ /* All site CSS lives here — built from scratch by the site/agency */
145
+ @import "../styles/custom-overrides.css";
146
+ ```
147
+
148
+ Do **not** import `fonts.css`, `theme.css`, `typography.css`, or any `style-overrides.*.css` — those belong to standard themed sites only.
149
+
150
+ #### 3. Define your own tokens in `custom-overrides.css`
151
+
152
+ Scope everything to `[data-theme="custom"]` so styles don't bleed into other contexts:
153
+
154
+ ```css
155
+ [data-theme="custom"] {
156
+ --font-body: "Your Font", sans-serif;
157
+ --font-display: "Your Display Font", serif;
158
+ --color-brand: #your-brand;
159
+ --color-bg: #0a0a0a;
160
+ --color-text: #f5f5f5;
161
+ }
162
+
163
+ [data-theme="custom"] body {
164
+ background-color: var(--color-bg);
165
+ color: var(--color-text);
166
+ font-family: var(--font-body);
167
+ -webkit-font-smoothing: antialiased;
168
+ }
169
+ ```
170
+
171
+ #### 4. Root layout
172
+
173
+ The root layout is the same as any other site — `KeystoneRootLayout` handles the HTML shell, meta tags, nav, and form/CTA wiring. It sets `data-theme="custom"` on `<html>` automatically based on the config.
174
+
175
+ ```typescript
176
+ // app/layout.tsx
177
+ import { KeystoneRootLayout } from 'keystone-design-bootstrap/next/layouts/root-layout';
178
+ import { config } from '@/config';
179
+
180
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
181
+ return <KeystoneRootLayout config={config}>{children}</KeystoneRootLayout>;
182
+ }
183
+ ```
184
+
185
+ ---
186
+
187
+ ### Using the API utilities
188
+
189
+ Data fetching works the same as any other site. All functions are server-only (use in `async` Server Components or Route Handlers — never in `'use client'` files).
190
+
191
+ **Environment variables** (`.env.local`):
192
+ ```
193
+ API_URL=http://localhost:3000/api/v1
194
+ API_KEY=your-api-key-here
195
+ ```
196
+
197
+ **Fetch data for a page — always use `Promise.all` to avoid waterfall requests:**
198
+
199
+ ```typescript
200
+ // app/page.tsx (Server Component)
201
+ import {
202
+ getCompanyInformation,
203
+ getServices,
204
+ getTestimonials,
205
+ getWebsitePhotos,
206
+ } from 'keystone-design-bootstrap/lib/server-api';
207
+
208
+ export default async function HomePage() {
209
+ const [company, services, testimonials, photos] = await Promise.all([
210
+ getCompanyInformation(),
211
+ getServices(),
212
+ getTestimonials(),
213
+ getWebsitePhotos(),
214
+ ]);
215
+
216
+ // Pass data as props to your custom components
217
+ return (
218
+ <>
219
+ <CustomHero company={company} photos={photos} />
220
+ <CustomServices services={services} />
221
+ <CustomTestimonials testimonials={testimonials} />
222
+ </>
223
+ );
224
+ }
225
+ ```
226
+
227
+ **Available fetch functions:**
228
+
229
+ | Function | Returns | Notes |
230
+ |----------|---------|-------|
231
+ | `getCompanyInformation()` | Business info, hours, portal URL | Used for CTAs, contact sections, layout |
232
+ | `getServices()` | `Service[]` | Each service has `service_items` with pricing/duration |
233
+ | `getService(slug)` | Single service | For `/services/[slug]` pages |
234
+ | `getPackages()` | `Package[]` | Bundled service items |
235
+ | `getPackage(slug)` | Single package | — |
236
+ | `getLocations()` | `Location[]` | — |
237
+ | `getLocation(slug)` | Single location | For `/locations/[slug]` pages |
238
+ | `getTestimonials()` | Reviews array | — |
239
+ | `getBlogPosts()` | Posts collection | — |
240
+ | `getBlogPost(slug)` | Single post | — |
241
+ | `getTeamMembers()` | Team array | — |
242
+ | `getJobPostings()` | Jobs array | — |
243
+ | `getJobPosting(slug)` | Single job | — |
244
+ | `getFAQs()` | FAQs array | — |
245
+ | `getSocialPosts()` | Social posts | — |
246
+ | `getWebsitePhotos()` | Photo slots (logo, hero, etc.) | — |
247
+
248
+ **Custom endpoints** not covered by a typed helper:
249
+
250
+ ```typescript
251
+ import { serverApi } from 'keystone-design-bootstrap/lib/server-api';
252
+
253
+ const data = await serverApi.get<MyType>('/public/some_resource');
254
+ // Force-fresh (bypass ISR cache):
255
+ const fresh = await serverApi.get<MyType>('/public/some_resource', { cache: 'no-store' });
256
+ ```
257
+
258
+ **Null safety:** every function returns `null` on network error or non-OK response. Always handle `null` — render an empty/fallback state rather than crashing.
259
+
260
+ See [`docs/server-api.md`](./docs/server-api.md) for full details on every function, caching options, and response shapes.
261
+
262
+ ---
263
+
105
264
  ## Creating a new theme
106
265
 
107
266
  See [`docs/theme-system.md`](./docs/theme-system.md) for the full guide.
@@ -114,4 +273,4 @@ Quick checklist:
114
273
  5. Add to design gallery
115
274
  6. `npm run lint && npm run typecheck && npm run build` — must all pass
116
275
 
117
- **Available themes:** `classic`, `aman`, `barelux`, `balance`
276
+ **Available themes:** `classic`, `aman`, `barelux`, `balance`, `custom`
@@ -9,8 +9,10 @@ var THEME_CONFIG = {
9
9
  // Aman Hotels variant files (hero-home.aman.tsx)
10
10
  barelux: ".barelux",
11
11
  // Bare Lux Studio variant files (hero-home.barelux.tsx)
12
- balance: ".balance"
12
+ balance: ".balance",
13
13
  // Balance Aesthetics variant files (hero-home.balance.tsx)
14
+ custom: ""
15
+ // Fully custom sites — no design-system CSS loaded, all styling built in the site itself
14
16
  };
15
17
  function isValidTheme(theme) {
16
18
  return theme in THEME_CONFIG;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/contexts/ThemeContext.tsx","../../src/themes/index.ts"],"sourcesContent":["'use client';\n\nimport { createContext, useContext } from 'react';\nimport { Theme, isValidTheme } from '../themes';\n\ninterface ThemeContextValue {\n theme: Theme;\n}\n\nconst ThemeContext = createContext<ThemeContextValue>({ theme: 'classic' });\n\nexport function ThemeProvider({ \n theme, \n children \n}: { \n theme: Theme; \n children: React.ReactNode;\n}) {\n // Validate theme at runtime\n if (!isValidTheme(theme)) {\n console.warn(`Invalid theme \"${theme}\", falling back to \"classic\"`);\n theme = 'classic';\n }\n \n return (\n <ThemeContext.Provider value={{ theme }}>\n {children}\n </ThemeContext.Provider>\n );\n}\n\nexport function useTheme() {\n return useContext(ThemeContext);\n}\n","/**\n * Theme Configuration\n * Single source of truth for all themes\n */\n\nexport const THEME_CONFIG = {\n classic: '', // Base files with no suffix (hero-home.tsx)\n aman: '.aman', // Aman Hotels variant files (hero-home.aman.tsx)\n barelux: '.barelux', // Bare Lux Studio variant files (hero-home.barelux.tsx)\n balance: '.balance', // Balance Aesthetics variant files (hero-home.balance.tsx)\n} as const;\n\nexport type Theme = keyof typeof THEME_CONFIG;\n\nexport function getAvailableThemes(): Theme[] {\n return Object.keys(THEME_CONFIG) as Theme[];\n}\n\nexport function getThemeSuffix(theme: Theme): string {\n return THEME_CONFIG[theme] || '';\n}\n\nexport function isValidTheme(theme: string): theme is Theme {\n return theme in THEME_CONFIG;\n}\n"],"mappings":";AAEA,SAAS,eAAe,kBAAkB;;;ACGnC,IAAM,eAAe;AAAA,EAC1B,SAAS;AAAA;AAAA,EACT,MAAM;AAAA;AAAA,EACN,SAAS;AAAA;AAAA,EACT,SAAS;AAAA;AACX;AAYO,SAAS,aAAa,OAA+B;AAC1D,SAAO,SAAS;AAClB;;;ADfA,IAAM,eAAe,cAAiC,EAAE,OAAO,UAAU,CAAC;AAEnE,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AACF,GAGG;AAED,MAAI,CAAC,aAAa,KAAK,GAAG;AACxB,YAAQ,KAAK,kBAAkB,KAAK,8BAA8B;AAClE,YAAQ;AAAA,EACV;AAEA,SACE,oCAAC,aAAa,UAAb,EAAsB,OAAO,EAAE,MAAM,KACnC,QACH;AAEJ;AAEO,SAAS,WAAW;AACzB,SAAO,WAAW,YAAY;AAChC;","names":[]}
1
+ {"version":3,"sources":["../../src/contexts/ThemeContext.tsx","../../src/themes/index.ts"],"sourcesContent":["'use client';\n\nimport { createContext, useContext } from 'react';\nimport { Theme, isValidTheme } from '../themes';\n\ninterface ThemeContextValue {\n theme: Theme;\n}\n\nconst ThemeContext = createContext<ThemeContextValue>({ theme: 'classic' });\n\nexport function ThemeProvider({ \n theme, \n children \n}: { \n theme: Theme; \n children: React.ReactNode;\n}) {\n // Validate theme at runtime\n if (!isValidTheme(theme)) {\n console.warn(`Invalid theme \"${theme}\", falling back to \"classic\"`);\n theme = 'classic';\n }\n \n return (\n <ThemeContext.Provider value={{ theme }}>\n {children}\n </ThemeContext.Provider>\n );\n}\n\nexport function useTheme() {\n return useContext(ThemeContext);\n}\n","/**\n * Theme Configuration\n * Single source of truth for all themes\n */\n\nexport const THEME_CONFIG = {\n classic: '', // Base files with no suffix (hero-home.tsx)\n aman: '.aman', // Aman Hotels variant files (hero-home.aman.tsx)\n barelux: '.barelux', // Bare Lux Studio variant files (hero-home.barelux.tsx)\n balance: '.balance', // Balance Aesthetics variant files (hero-home.balance.tsx)\n custom: '', // Fully custom sites — no design-system CSS loaded, all styling built in the site itself\n} as const;\n\nexport type Theme = keyof typeof THEME_CONFIG;\n\nexport function getAvailableThemes(): Theme[] {\n return Object.keys(THEME_CONFIG) as Theme[];\n}\n\nexport function getThemeSuffix(theme: Theme): string {\n return THEME_CONFIG[theme] || '';\n}\n\nexport function isValidTheme(theme: string): theme is Theme {\n return theme in THEME_CONFIG;\n}\n"],"mappings":";AAEA,SAAS,eAAe,kBAAkB;;;ACGnC,IAAM,eAAe;AAAA,EAC1B,SAAS;AAAA;AAAA,EACT,MAAM;AAAA;AAAA,EACN,SAAS;AAAA;AAAA,EACT,SAAS;AAAA;AAAA,EACT,QAAQ;AAAA;AACV;AAYO,SAAS,aAAa,OAA+B;AAC1D,SAAO,SAAS;AAClB;;;ADhBA,IAAM,eAAe,cAAiC,EAAE,OAAO,UAAU,CAAC;AAEnE,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AACF,GAGG;AAED,MAAI,CAAC,aAAa,KAAK,GAAG;AACxB,YAAQ,KAAK,kBAAkB,KAAK,8BAA8B;AAClE,YAAQ;AAAA,EACV;AAEA,SACE,oCAAC,aAAa,UAAb,EAAsB,OAAO,EAAE,MAAM,KACnC,QACH;AAEJ;AAEO,SAAS,WAAW;AACzB,SAAO,WAAW,YAAY;AAChC;","names":[]}
package/dist/index.js CHANGED
@@ -72,8 +72,10 @@ var THEME_CONFIG = {
72
72
  // Aman Hotels variant files (hero-home.aman.tsx)
73
73
  barelux: ".barelux",
74
74
  // Bare Lux Studio variant files (hero-home.barelux.tsx)
75
- balance: ".balance"
75
+ balance: ".balance",
76
76
  // Balance Aesthetics variant files (hero-home.balance.tsx)
77
+ custom: ""
78
+ // Fully custom sites — no design-system CSS loaded, all styling built in the site itself
77
79
  };
78
80
  function isValidTheme(theme) {
79
81
  return theme in THEME_CONFIG;