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 +160 -1
- package/dist/contexts/index.js +3 -1
- package/dist/contexts/index.js.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/themes/index.d.ts +1 -0
- package/dist/themes/index.js +3 -1
- package/dist/themes/index.js.map +1 -1
- package/package.json +1 -1
- package/src/next/layouts/root-layout.tsx +16 -12
- package/src/themes/index.ts +1 -0
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`
|
package/dist/contexts/index.js
CHANGED
|
@@ -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;
|
|
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;
|