@olonjs/cli 3.0.81 → 3.0.83

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.
@@ -596,7 +596,7 @@ cat << 'END_OF_FILE_CONTENT' > "package.json"
596
596
  "@tiptap/extension-link": "^2.11.5",
597
597
  "@tiptap/react": "^2.11.5",
598
598
  "@tiptap/starter-kit": "^2.11.5",
599
- "@olonjs/core": "^1.0.69",
599
+ "@olonjs/core": "^1.0.71",
600
600
  "clsx": "^2.1.1",
601
601
  "lucide-react": "^0.474.0",
602
602
  "react": "^19.0.0",
@@ -941,6 +941,7 @@ import themeData from '@/data/config/theme.json';
941
941
  import menuData from '@/data/config/menu.json';
942
942
  import { getFilePages } from '@/lib/getFilePages';
943
943
  import { DopaDrawer } from '@/components/save-drawer/DopaDrawer';
944
+ import { Skeleton } from '@/components/ui/skeleton';
944
945
 
945
946
  import tenantCss from './index.css?inline';
946
947
 
@@ -1194,6 +1195,16 @@ function cloudFingerprint(apiBase: string, apiKey: string): string {
1194
1195
  return `${normalizeApiBase(apiBase)}::${apiKey.slice(-8)}`;
1195
1196
  }
1196
1197
 
1198
+ function normalizeSlugForCache(slug: string): string {
1199
+ return (
1200
+ slug
1201
+ .trim()
1202
+ .toLowerCase()
1203
+ .replace(/[^a-z0-9/_-]/g, '-')
1204
+ .replace(/^\/+|\/+$/g, '') || 'home'
1205
+ );
1206
+ }
1207
+
1197
1208
  function readCachedCloudContent(fingerprint: string): CachedCloudContent | null {
1198
1209
  try {
1199
1210
  const raw = localStorage.getItem(CLOUD_CACHE_KEY);
@@ -1248,7 +1259,6 @@ function App() {
1248
1259
  const activeCloudSaveController = useRef<AbortController | null>(null);
1249
1260
  const contentLoadInFlight = useRef<Promise<void> | null>(null);
1250
1261
  const pendingCloudSave = useRef<{ state: ProjectState; slug: string } | null>(null);
1251
- const warmBootFromCloudCache = useRef(false);
1252
1262
  const cloudApiCandidates = useMemo(
1253
1263
  () => (isCloudMode && CLOUD_API_URL ? buildApiCandidates(CLOUD_API_URL) : []),
1254
1264
  [isCloudMode, CLOUD_API_URL]
@@ -1288,26 +1298,16 @@ function App() {
1288
1298
  const primaryApiBase = cloudApiCandidates[0] ?? normalizeApiBase(CLOUD_API_URL);
1289
1299
  const fingerprint = cloudFingerprint(primaryApiBase, CLOUD_API_KEY);
1290
1300
  const cached = readCachedCloudContent(fingerprint);
1301
+ const cachedPages = cached ? toPagesRecord(cached.pages) : null;
1302
+ const cachedSite = cached ? coerceSiteConfig(cached.siteConfig) : null;
1303
+ const hasCachedFallback = Boolean((cachedPages && Object.keys(cachedPages).length > 0) || cachedSite);
1291
1304
  if (cached) {
1292
- const cachedPages = toPagesRecord(cached.pages);
1293
- const cachedSite = coerceSiteConfig(cached.siteConfig);
1294
- if (cachedPages && Object.keys(cachedPages).length > 0) {
1295
- setPages(cachedPages);
1296
- }
1297
- if (cachedSite) {
1298
- setSiteConfig(cachedSite);
1299
- }
1300
- setContentMode('cloud');
1301
- setContentFallback(null);
1302
- warmBootFromCloudCache.current = true;
1303
- setShowTopProgress(false);
1304
- setHasInitialCloudResolved(true);
1305
1305
  logBootstrapEvent('boot.cloud.cache_hit', { ageMs: Date.now() - cached.savedAt });
1306
- } else {
1307
- warmBootFromCloudCache.current = false;
1308
- setShowTopProgress(true);
1309
- setHasInitialCloudResolved(false);
1310
1306
  }
1307
+ setContentMode('cloud');
1308
+ setContentFallback(null);
1309
+ setShowTopProgress(true);
1310
+ setHasInitialCloudResolved(false);
1311
1311
  logBootstrapEvent('boot.start', { mode: 'cloud', apiCandidates: cloudApiCandidates.length });
1312
1312
 
1313
1313
  const loadCloudContent = async () => {
@@ -1320,6 +1320,7 @@ function App() {
1320
1320
  try {
1321
1321
  const res = await fetch(`${apiBase}/content`, {
1322
1322
  method: 'GET',
1323
+ cache: 'no-store',
1323
1324
  headers: {
1324
1325
  Authorization: `Bearer ${CLOUD_API_KEY}`,
1325
1326
  },
@@ -1422,7 +1423,13 @@ function App() {
1422
1423
  } catch (error: unknown) {
1423
1424
  if (controller.signal.aborted) return;
1424
1425
  const failure = toCloudLoadFailure(error);
1425
- if (warmBootFromCloudCache.current) {
1426
+ if (hasCachedFallback) {
1427
+ if (cachedPages && Object.keys(cachedPages).length > 0) {
1428
+ setPages(cachedPages);
1429
+ }
1430
+ if (cachedSite) {
1431
+ setSiteConfig(cachedSite);
1432
+ }
1426
1433
  setContentMode('cloud');
1427
1434
  setContentFallback({
1428
1435
  reasonCode: 'CLOUD_REFRESH_FAILED',
@@ -1589,14 +1596,26 @@ function App() {
1589
1596
  },
1590
1597
  body: JSON.stringify({
1591
1598
  slug,
1592
- type: 'page',
1593
- data: state.page,
1599
+ page: state.page,
1600
+ siteConfig: state.site,
1594
1601
  }),
1595
1602
  });
1596
1603
  const body = (await res.json().catch(() => ({}))) as { error?: string; code?: string };
1597
1604
  if (!res.ok) {
1598
1605
  throw new Error(body.error || body.code || `Hot save failed: ${res.status}`);
1599
1606
  }
1607
+ const keyFingerprint = cloudFingerprint(apiBase, CLOUD_API_KEY);
1608
+ const normalizedSlug = normalizeSlugForCache(slug);
1609
+ const existing = readCachedCloudContent(keyFingerprint);
1610
+ writeCachedCloudContent({
1611
+ keyFingerprint,
1612
+ savedAt: Date.now(),
1613
+ siteConfig: state.site ?? null,
1614
+ pages: {
1615
+ ...(existing?.pages ?? {}),
1616
+ [normalizedSlug]: state.page,
1617
+ },
1618
+ });
1600
1619
  },
1601
1620
  showLegacySave: !isCloudMode,
1602
1621
  showHotSave: isCloudMode,
@@ -1667,6 +1686,26 @@ function App() {
1667
1686
  </div>
1668
1687
  </>
1669
1688
  ) : null}
1689
+ {isCloudMode && !hasInitialCloudResolved ? (
1690
+ <div className="fixed inset-0 z-[1290] bg-background/80 backdrop-blur-sm">
1691
+ <div className="mx-auto w-full max-w-[1600px] p-6">
1692
+ <div className="grid gap-4 lg:grid-cols-[1fr_420px]">
1693
+ <div className="space-y-4">
1694
+ <Skeleton className="h-10 w-64" />
1695
+ <Skeleton className="h-[220px] w-full rounded-xl" />
1696
+ <Skeleton className="h-[220px] w-full rounded-xl" />
1697
+ </div>
1698
+ <div className="space-y-3 rounded-xl border border-border/50 bg-card/60 p-4">
1699
+ <Skeleton className="h-8 w-32" />
1700
+ <Skeleton className="h-5 w-full" />
1701
+ <Skeleton className="h-5 w-5/6" />
1702
+ <Skeleton className="h-5 w-4/6" />
1703
+ <Skeleton className="h-24 w-full rounded-lg" />
1704
+ </div>
1705
+ </div>
1706
+ </div>
1707
+ </div>
1708
+ ) : null}
1670
1709
  {shouldRenderEngine ? <JsonPagesEngine config={config} /> : null}
1671
1710
  {isCloudMode && (contentMode === 'error' || contentFallback?.reasonCode === 'CLOUD_REFRESH_FAILED') ? (
1672
1711
  <div
@@ -3467,7 +3506,7 @@ echo "Creating src/components/header/View.tsx..."
3467
3506
  cat << 'END_OF_FILE_CONTENT' > "src/components/header/View.tsx"
3468
3507
  import React, { useState, useEffect } from 'react';
3469
3508
  import { cn } from '@/lib/utils';
3470
- import type { MenuItem } from '@jsonpages/core';
3509
+ import type { MenuItem } from '@olonjs/core';
3471
3510
  import type { HeaderData, HeaderSettings } from './types';
3472
3511
 
3473
3512
  export const Header: React.FC<{
@@ -3891,7 +3930,7 @@ mkdir -p "src/components/image-break"
3891
3930
  echo "Creating src/components/image-break/View.tsx..."
3892
3931
  cat << 'END_OF_FILE_CONTENT' > "src/components/image-break/View.tsx"
3893
3932
  import React from 'react';
3894
- import { resolveAssetUrl, useConfig } from '@jsonpages/core';
3933
+ import { resolveAssetUrl, useConfig } from '@olonjs/core';
3895
3934
  import type { ImageBreakData, ImageBreakSettings } from './types';
3896
3935
 
3897
3936
  export const ImageBreak: React.FC<{ data: ImageBreakData; settings?: ImageBreakSettings }> = ({ data }) => {
@@ -7186,6 +7225,26 @@ export { Separator }
7186
7225
 
7187
7226
 
7188
7227
 
7228
+ END_OF_FILE_CONTENT
7229
+ echo "Creating src/components/ui/skeleton.tsx..."
7230
+ cat << 'END_OF_FILE_CONTENT' > "src/components/ui/skeleton.tsx"
7231
+ import { cn } from '@/lib/utils';
7232
+ import type { HTMLAttributes } from 'react';
7233
+
7234
+ function Skeleton({
7235
+ className,
7236
+ ...props
7237
+ }: HTMLAttributes<HTMLDivElement>) {
7238
+ return (
7239
+ <div
7240
+ className={cn('animate-pulse rounded-md bg-muted', className)}
7241
+ {...props}
7242
+ />
7243
+ );
7244
+ }
7245
+
7246
+ export { Skeleton };
7247
+
7189
7248
  END_OF_FILE_CONTENT
7190
7249
  echo "Creating src/components/ui/textarea.tsx..."
7191
7250
  cat << 'END_OF_FILE_CONTENT' > "src/components/ui/textarea.tsx"
@@ -596,7 +596,7 @@ cat << 'END_OF_FILE_CONTENT' > "package.json"
596
596
  "@tiptap/extension-link": "^2.11.5",
597
597
  "@tiptap/react": "^2.11.5",
598
598
  "@tiptap/starter-kit": "^2.11.5",
599
- "@olonjs/core": "^1.0.69",
599
+ "@olonjs/core": "^1.0.71",
600
600
  "clsx": "^2.1.1",
601
601
  "lucide-react": "^0.474.0",
602
602
  "react": "^19.0.0",
@@ -1074,6 +1074,30 @@ function App() {
1074
1074
  const body = (await res.json().catch(() => ({}))) as { error?: string };
1075
1075
  if (!res.ok) throw new Error(body.error ?? `Save to file failed: ${res.status}`);
1076
1076
  },
1077
+ async hotSave(state: ProjectState, slug: string): Promise<void> {
1078
+ if (!isCloudMode || !CLOUD_API_URL || !CLOUD_API_KEY) {
1079
+ throw new Error('Cloud mode is not configured for hot save.');
1080
+ }
1081
+ const apiBase = CLOUD_API_URL.replace(/\/$/, '');
1082
+ const res = await fetch(`${apiBase}/hotSave`, {
1083
+ method: 'POST',
1084
+ headers: {
1085
+ 'Content-Type': 'application/json',
1086
+ Authorization: `Bearer ${CLOUD_API_KEY}`,
1087
+ },
1088
+ body: JSON.stringify({
1089
+ slug,
1090
+ page: state.page,
1091
+ siteConfig: state.site,
1092
+ }),
1093
+ });
1094
+ const body = (await res.json().catch(() => ({}))) as { error?: string; code?: string };
1095
+ if (!res.ok) {
1096
+ throw new Error(body.error || body.code || `Hot save failed: ${res.status}`);
1097
+ }
1098
+ },
1099
+ showLegacySave: !isCloudMode,
1100
+ showHotSave: isCloudMode,
1077
1101
  },
1078
1102
  assets: {
1079
1103
  assetsBaseUrl: '/assets',
@@ -2321,7 +2345,7 @@ cat << 'END_OF_FILE_CONTENT' > "src/components/contact-form/View.tsx"
2321
2345
  import React, { useCallback, useState } from 'react';
2322
2346
  import { useInView } from '@/lib/useInView';
2323
2347
  import { useFormSubmit } from '@/lib/useFormSubmit';
2324
- import { useConfig } from '@jsonpages/core';
2348
+ import { useConfig } from '@olonjs/core';
2325
2349
  import type { ContactFormData, ContactFormSettings } from './types';
2326
2350
 
2327
2351
  const inputCls = `
@@ -2695,7 +2719,7 @@ mkdir -p "src/components/cta-nature"
2695
2719
  echo "Creating src/components/cta-nature/View.tsx..."
2696
2720
  cat << 'END_OF_FILE_CONTENT' > "src/components/cta-nature/View.tsx"
2697
2721
  import React from 'react';
2698
- import { resolveAssetUrl, useConfig } from '@jsonpages/core';
2722
+ import { resolveAssetUrl, useConfig } from '@olonjs/core';
2699
2723
  import type { CtaNatureData, CtaNatureSettings } from './types';
2700
2724
  import type { SiteConfig } from '@/types';
2701
2725
  import type { HeaderData } from '@/components/header';
@@ -3448,7 +3472,7 @@ mkdir -p "src/components/footer"
3448
3472
  echo "Creating src/components/footer/View.tsx..."
3449
3473
  cat << 'END_OF_FILE_CONTENT' > "src/components/footer/View.tsx"
3450
3474
  import React, { useEffect, useState } from 'react';
3451
- import { resolveAssetUrl, useConfig } from '@jsonpages/core';
3475
+ import { resolveAssetUrl, useConfig } from '@olonjs/core';
3452
3476
  import type { FooterData, FooterSettings } from './types';
3453
3477
 
3454
3478
  export const Footer: React.FC<{ data: FooterData; settings?: FooterSettings }> = ({ data }) => {
@@ -3888,9 +3912,9 @@ mkdir -p "src/components/header"
3888
3912
  echo "Creating src/components/header/View.tsx..."
3889
3913
  cat << 'END_OF_FILE_CONTENT' > "src/components/header/View.tsx"
3890
3914
  import React, { useState, useEffect } from 'react';
3891
- import { resolveAssetUrl, useConfig } from '@jsonpages/core';
3915
+ import { resolveAssetUrl, useConfig } from '@olonjs/core';
3892
3916
  import type { HeaderData, HeaderSettings } from './types';
3893
- import type { MenuItem } from '@jsonpages/core';
3917
+ import type { MenuItem } from '@olonjs/core';
3894
3918
 
3895
3919
  interface HeaderProps {
3896
3920
  data: HeaderData;
@@ -4303,7 +4327,7 @@ mkdir -p "src/components/image-break"
4303
4327
  echo "Creating src/components/image-break/View.tsx..."
4304
4328
  cat << 'END_OF_FILE_CONTENT' > "src/components/image-break/View.tsx"
4305
4329
  import React from 'react';
4306
- import { resolveAssetUrl, useConfig } from '@jsonpages/core';
4330
+ import { resolveAssetUrl, useConfig } from '@olonjs/core';
4307
4331
  import type { ImageBreakData, ImageBreakSettings } from './types';
4308
4332
 
4309
4333
  export const ImageBreak: React.FC<{ data: ImageBreakData; settings?: ImageBreakSettings }> = ({ data }) => {
@@ -596,7 +596,7 @@ cat << 'END_OF_FILE_CONTENT' > "package.json"
596
596
  "@tiptap/extension-link": "^2.11.5",
597
597
  "@tiptap/react": "^2.11.5",
598
598
  "@tiptap/starter-kit": "^2.11.5",
599
- "@olonjs/core": "^1.0.69",
599
+ "@olonjs/core": "^1.0.71",
600
600
  "clsx": "^2.1.1",
601
601
  "lucide-react": "^0.474.0",
602
602
  "react": "^19.0.0",
@@ -941,6 +941,7 @@ import themeData from '@/data/config/theme.json';
941
941
  import menuData from '@/data/config/menu.json';
942
942
  import { getFilePages } from '@/lib/getFilePages';
943
943
  import { DopaDrawer } from '@/components/save-drawer/DopaDrawer';
944
+ import { Skeleton } from '@/components/ui/skeleton';
944
945
 
945
946
  import tenantCss from './index.css?inline';
946
947
 
@@ -1194,6 +1195,16 @@ function cloudFingerprint(apiBase: string, apiKey: string): string {
1194
1195
  return `${normalizeApiBase(apiBase)}::${apiKey.slice(-8)}`;
1195
1196
  }
1196
1197
 
1198
+ function normalizeSlugForCache(slug: string): string {
1199
+ return (
1200
+ slug
1201
+ .trim()
1202
+ .toLowerCase()
1203
+ .replace(/[^a-z0-9/_-]/g, '-')
1204
+ .replace(/^\/+|\/+$/g, '') || 'home'
1205
+ );
1206
+ }
1207
+
1197
1208
  function readCachedCloudContent(fingerprint: string): CachedCloudContent | null {
1198
1209
  try {
1199
1210
  const raw = localStorage.getItem(CLOUD_CACHE_KEY);
@@ -1248,7 +1259,6 @@ function App() {
1248
1259
  const activeCloudSaveController = useRef<AbortController | null>(null);
1249
1260
  const contentLoadInFlight = useRef<Promise<void> | null>(null);
1250
1261
  const pendingCloudSave = useRef<{ state: ProjectState; slug: string } | null>(null);
1251
- const warmBootFromCloudCache = useRef(false);
1252
1262
  const cloudApiCandidates = useMemo(
1253
1263
  () => (isCloudMode && CLOUD_API_URL ? buildApiCandidates(CLOUD_API_URL) : []),
1254
1264
  [isCloudMode, CLOUD_API_URL]
@@ -1288,26 +1298,16 @@ function App() {
1288
1298
  const primaryApiBase = cloudApiCandidates[0] ?? normalizeApiBase(CLOUD_API_URL);
1289
1299
  const fingerprint = cloudFingerprint(primaryApiBase, CLOUD_API_KEY);
1290
1300
  const cached = readCachedCloudContent(fingerprint);
1301
+ const cachedPages = cached ? toPagesRecord(cached.pages) : null;
1302
+ const cachedSite = cached ? coerceSiteConfig(cached.siteConfig) : null;
1303
+ const hasCachedFallback = Boolean((cachedPages && Object.keys(cachedPages).length > 0) || cachedSite);
1291
1304
  if (cached) {
1292
- const cachedPages = toPagesRecord(cached.pages);
1293
- const cachedSite = coerceSiteConfig(cached.siteConfig);
1294
- if (cachedPages && Object.keys(cachedPages).length > 0) {
1295
- setPages(cachedPages);
1296
- }
1297
- if (cachedSite) {
1298
- setSiteConfig(cachedSite);
1299
- }
1300
- setContentMode('cloud');
1301
- setContentFallback(null);
1302
- warmBootFromCloudCache.current = true;
1303
- setShowTopProgress(false);
1304
- setHasInitialCloudResolved(true);
1305
1305
  logBootstrapEvent('boot.cloud.cache_hit', { ageMs: Date.now() - cached.savedAt });
1306
- } else {
1307
- warmBootFromCloudCache.current = false;
1308
- setShowTopProgress(true);
1309
- setHasInitialCloudResolved(false);
1310
1306
  }
1307
+ setContentMode('cloud');
1308
+ setContentFallback(null);
1309
+ setShowTopProgress(true);
1310
+ setHasInitialCloudResolved(false);
1311
1311
  logBootstrapEvent('boot.start', { mode: 'cloud', apiCandidates: cloudApiCandidates.length });
1312
1312
 
1313
1313
  const loadCloudContent = async () => {
@@ -1320,6 +1320,7 @@ function App() {
1320
1320
  try {
1321
1321
  const res = await fetch(`${apiBase}/content`, {
1322
1322
  method: 'GET',
1323
+ cache: 'no-store',
1323
1324
  headers: {
1324
1325
  Authorization: `Bearer ${CLOUD_API_KEY}`,
1325
1326
  },
@@ -1422,7 +1423,13 @@ function App() {
1422
1423
  } catch (error: unknown) {
1423
1424
  if (controller.signal.aborted) return;
1424
1425
  const failure = toCloudLoadFailure(error);
1425
- if (warmBootFromCloudCache.current) {
1426
+ if (hasCachedFallback) {
1427
+ if (cachedPages && Object.keys(cachedPages).length > 0) {
1428
+ setPages(cachedPages);
1429
+ }
1430
+ if (cachedSite) {
1431
+ setSiteConfig(cachedSite);
1432
+ }
1426
1433
  setContentMode('cloud');
1427
1434
  setContentFallback({
1428
1435
  reasonCode: 'CLOUD_REFRESH_FAILED',
@@ -1589,14 +1596,26 @@ function App() {
1589
1596
  },
1590
1597
  body: JSON.stringify({
1591
1598
  slug,
1592
- type: 'page',
1593
- data: state.page,
1599
+ page: state.page,
1600
+ siteConfig: state.site,
1594
1601
  }),
1595
1602
  });
1596
1603
  const body = (await res.json().catch(() => ({}))) as { error?: string; code?: string };
1597
1604
  if (!res.ok) {
1598
1605
  throw new Error(body.error || body.code || `Hot save failed: ${res.status}`);
1599
1606
  }
1607
+ const keyFingerprint = cloudFingerprint(apiBase, CLOUD_API_KEY);
1608
+ const normalizedSlug = normalizeSlugForCache(slug);
1609
+ const existing = readCachedCloudContent(keyFingerprint);
1610
+ writeCachedCloudContent({
1611
+ keyFingerprint,
1612
+ savedAt: Date.now(),
1613
+ siteConfig: state.site ?? null,
1614
+ pages: {
1615
+ ...(existing?.pages ?? {}),
1616
+ [normalizedSlug]: state.page,
1617
+ },
1618
+ });
1600
1619
  },
1601
1620
  showLegacySave: !isCloudMode,
1602
1621
  showHotSave: isCloudMode,
@@ -1667,6 +1686,26 @@ function App() {
1667
1686
  </div>
1668
1687
  </>
1669
1688
  ) : null}
1689
+ {isCloudMode && !hasInitialCloudResolved ? (
1690
+ <div className="fixed inset-0 z-[1290] bg-background/80 backdrop-blur-sm">
1691
+ <div className="mx-auto w-full max-w-[1600px] p-6">
1692
+ <div className="grid gap-4 lg:grid-cols-[1fr_420px]">
1693
+ <div className="space-y-4">
1694
+ <Skeleton className="h-10 w-64" />
1695
+ <Skeleton className="h-[220px] w-full rounded-xl" />
1696
+ <Skeleton className="h-[220px] w-full rounded-xl" />
1697
+ </div>
1698
+ <div className="space-y-3 rounded-xl border border-border/50 bg-card/60 p-4">
1699
+ <Skeleton className="h-8 w-32" />
1700
+ <Skeleton className="h-5 w-full" />
1701
+ <Skeleton className="h-5 w-5/6" />
1702
+ <Skeleton className="h-5 w-4/6" />
1703
+ <Skeleton className="h-24 w-full rounded-lg" />
1704
+ </div>
1705
+ </div>
1706
+ </div>
1707
+ </div>
1708
+ ) : null}
1670
1709
  {shouldRenderEngine ? <JsonPagesEngine config={config} /> : null}
1671
1710
  {isCloudMode && (contentMode === 'error' || contentFallback?.reasonCode === 'CLOUD_REFRESH_FAILED') ? (
1672
1711
  <div
@@ -3467,7 +3506,7 @@ echo "Creating src/components/header/View.tsx..."
3467
3506
  cat << 'END_OF_FILE_CONTENT' > "src/components/header/View.tsx"
3468
3507
  import React, { useState, useEffect } from 'react';
3469
3508
  import { cn } from '@/lib/utils';
3470
- import type { MenuItem } from '@jsonpages/core';
3509
+ import type { MenuItem } from '@olonjs/core';
3471
3510
  import type { HeaderData, HeaderSettings } from './types';
3472
3511
 
3473
3512
  export const Header: React.FC<{
@@ -3891,7 +3930,7 @@ mkdir -p "src/components/image-break"
3891
3930
  echo "Creating src/components/image-break/View.tsx..."
3892
3931
  cat << 'END_OF_FILE_CONTENT' > "src/components/image-break/View.tsx"
3893
3932
  import React from 'react';
3894
- import { resolveAssetUrl, useConfig } from '@jsonpages/core';
3933
+ import { resolveAssetUrl, useConfig } from '@olonjs/core';
3895
3934
  import type { ImageBreakData, ImageBreakSettings } from './types';
3896
3935
 
3897
3936
  export const ImageBreak: React.FC<{ data: ImageBreakData; settings?: ImageBreakSettings }> = ({ data }) => {
@@ -7186,6 +7225,26 @@ export { Separator }
7186
7225
 
7187
7226
 
7188
7227
 
7228
+ END_OF_FILE_CONTENT
7229
+ echo "Creating src/components/ui/skeleton.tsx..."
7230
+ cat << 'END_OF_FILE_CONTENT' > "src/components/ui/skeleton.tsx"
7231
+ import { cn } from '@/lib/utils';
7232
+ import type { HTMLAttributes } from 'react';
7233
+
7234
+ function Skeleton({
7235
+ className,
7236
+ ...props
7237
+ }: HTMLAttributes<HTMLDivElement>) {
7238
+ return (
7239
+ <div
7240
+ className={cn('animate-pulse rounded-md bg-muted', className)}
7241
+ {...props}
7242
+ />
7243
+ );
7244
+ }
7245
+
7246
+ export { Skeleton };
7247
+
7189
7248
  END_OF_FILE_CONTENT
7190
7249
  echo "Creating src/components/ui/textarea.tsx..."
7191
7250
  cat << 'END_OF_FILE_CONTENT' > "src/components/ui/textarea.tsx"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@olonjs/cli",
3
- "version": "3.0.81",
3
+ "version": "3.0.83",
4
4
  "description": "The Sovereign CLI Engine for OlonJS.",
5
5
  "type": "module",
6
6
  "bin": {