@thewhateverapp/tile-sdk 0.13.3 → 0.13.4
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/dist/templates/slideshow/index.d.ts +9 -1
- package/dist/templates/slideshow/index.d.ts.map +1 -1
- package/dist/templates/slideshow/index.js +11 -3
- package/dist/templates/slideshow/layout.tsx.template.d.ts +18 -0
- package/dist/templates/slideshow/layout.tsx.template.d.ts.map +1 -1
- package/dist/templates/slideshow/layout.tsx.template.js +187 -0
- package/dist/templates/video/index.d.ts +9 -1
- package/dist/templates/video/index.d.ts.map +1 -1
- package/dist/templates/video/index.js +11 -3
- package/dist/templates/video/layout.tsx.template.d.ts +18 -0
- package/dist/templates/video/layout.tsx.template.d.ts.map +1 -1
- package/dist/templates/video/layout.tsx.template.js +192 -0
- package/package.json +1 -1
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* - Tile and page routes only render overlay content
|
|
10
10
|
* - This ensures seamless state persistence across navigation
|
|
11
11
|
*/
|
|
12
|
-
export { slideshowLayoutTemplate, slideshowTileOverlayTemplate, slideshowPageOverlayTemplate, } from './layout.tsx.template.js';
|
|
12
|
+
export { slideshowLayoutTemplate, slideshowTileOverlayTemplate, slideshowPageOverlayTemplate, slideshowPreviewTileTemplate, slideshowPreviewPageTemplate, } from './layout.tsx.template.js';
|
|
13
13
|
export { slideshowManagerTemplate } from './SlideshowManager.ts.template.js';
|
|
14
14
|
export { persistentSlideshowTemplate } from './PersistentSlideshow.tsx.template.js';
|
|
15
15
|
/**
|
|
@@ -21,6 +21,14 @@ export declare const slideshowTemplateFiles: {
|
|
|
21
21
|
'src/app/(slideshow)/tile/page.tsx': string;
|
|
22
22
|
'src/app/(slideshow)/page/page.tsx': string;
|
|
23
23
|
};
|
|
24
|
+
/**
|
|
25
|
+
* Preview entry files for tile-preview bundling.
|
|
26
|
+
* These combine Slideshow + overlay since tile-preview doesn't understand Next.js layouts.
|
|
27
|
+
*/
|
|
28
|
+
export declare const slideshowPreviewFiles: {
|
|
29
|
+
'src/app/_preview/tile.tsx': string;
|
|
30
|
+
'src/app/_preview/page.tsx': string;
|
|
31
|
+
};
|
|
24
32
|
export declare const slideshowLegacyTemplateFiles: {
|
|
25
33
|
'src/shared/lib/SlideshowManager.ts': string;
|
|
26
34
|
'src/shared/components/PersistentSlideshow.tsx': string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/slideshow/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EACL,uBAAuB,EACvB,4BAA4B,EAC5B,4BAA4B,GAC7B,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAC7E,OAAO,EAAE,2BAA2B,EAAE,MAAM,uCAAuC,CAAC;AAEpF;;;GAGG;AACH,eAAO,MAAM,sBAAsB;;;;CAMlC,CAAC;AAGF,eAAO,MAAM,4BAA4B;;;CAGxC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/slideshow/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EACL,uBAAuB,EACvB,4BAA4B,EAC5B,4BAA4B,EAC5B,4BAA4B,EAC5B,4BAA4B,GAC7B,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAC7E,OAAO,EAAE,2BAA2B,EAAE,MAAM,uCAAuC,CAAC;AAEpF;;;GAGG;AACH,eAAO,MAAM,sBAAsB;;;;CAMlC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,qBAAqB;;;CAGjC,CAAC;AAGF,eAAO,MAAM,4BAA4B;;;CAGxC,CAAC"}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* - This ensures seamless state persistence across navigation
|
|
11
11
|
*/
|
|
12
12
|
// ESM requires explicit .js extension for imports
|
|
13
|
-
export { slideshowLayoutTemplate, slideshowTileOverlayTemplate, slideshowPageOverlayTemplate, } from './layout.tsx.template.js';
|
|
13
|
+
export { slideshowLayoutTemplate, slideshowTileOverlayTemplate, slideshowPageOverlayTemplate, slideshowPreviewTileTemplate, slideshowPreviewPageTemplate, } from './layout.tsx.template.js';
|
|
14
14
|
// Legacy templates (kept for backwards compatibility)
|
|
15
15
|
export { slideshowManagerTemplate } from './SlideshowManager.ts.template.js';
|
|
16
16
|
export { persistentSlideshowTemplate } from './PersistentSlideshow.tsx.template.js';
|
|
@@ -19,12 +19,20 @@ export { persistentSlideshowTemplate } from './PersistentSlideshow.tsx.template.
|
|
|
19
19
|
* The (slideshow) route group ensures state persists across tile/page navigation.
|
|
20
20
|
*/
|
|
21
21
|
export const slideshowTemplateFiles = {
|
|
22
|
-
// Layout mounts Slideshow once
|
|
22
|
+
// Layout mounts Slideshow once (for production - Next.js applies this)
|
|
23
23
|
'src/app/(slideshow)/layout.tsx': 'slideshowLayoutTemplate',
|
|
24
|
-
// Overlay-only pages (no Slideshow wrapper needed)
|
|
24
|
+
// Overlay-only pages (no Slideshow wrapper needed in production)
|
|
25
25
|
'src/app/(slideshow)/tile/page.tsx': 'slideshowTileOverlayTemplate',
|
|
26
26
|
'src/app/(slideshow)/page/page.tsx': 'slideshowPageOverlayTemplate',
|
|
27
27
|
};
|
|
28
|
+
/**
|
|
29
|
+
* Preview entry files for tile-preview bundling.
|
|
30
|
+
* These combine Slideshow + overlay since tile-preview doesn't understand Next.js layouts.
|
|
31
|
+
*/
|
|
32
|
+
export const slideshowPreviewFiles = {
|
|
33
|
+
'src/app/_preview/tile.tsx': 'slideshowPreviewTileTemplate',
|
|
34
|
+
'src/app/_preview/page.tsx': 'slideshowPreviewPageTemplate',
|
|
35
|
+
};
|
|
28
36
|
// Legacy file structure (deprecated)
|
|
29
37
|
export const slideshowLegacyTemplateFiles = {
|
|
30
38
|
'src/shared/lib/SlideshowManager.ts': 'slideshowManagerTemplate',
|
|
@@ -26,4 +26,22 @@ export declare const slideshowTileOverlayTemplate = "'use client';\n\nimport { u
|
|
|
26
26
|
* File path: src/app/(slideshow)/page/page.tsx
|
|
27
27
|
*/
|
|
28
28
|
export declare const slideshowPageOverlayTemplate = "'use client';\n\nimport { useSlideshowState, OverlaySlot, GradientOverlay } from '@thewhateverapp/tile-sdk';\n\nexport default function PageOverlay() {\n const { state, controls } = useSlideshowState();\n\n return (\n <>\n {/* Slide counter */}\n <OverlaySlot position=\"top-right\">\n <div className=\"bg-black/50 backdrop-blur-sm px-3 py-1.5 rounded-full text-sm text-white\">\n {state.currentIndex + 1} / {state.totalSlides}\n </div>\n </OverlaySlot>\n\n {/* Navigation arrows (larger for full page) */}\n <OverlaySlot position=\"center-left\">\n <button\n onClick={controls.prev}\n className=\"bg-black/40 backdrop-blur-sm p-3 rounded-full text-white hover:bg-black/60 transition-colors\"\n aria-label=\"Previous slide\"\n >\n <svg className=\"w-6 h-6\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M15 19l-7-7 7-7\" />\n </svg>\n </button>\n </OverlaySlot>\n\n <OverlaySlot position=\"center-right\">\n <button\n onClick={controls.next}\n className=\"bg-black/40 backdrop-blur-sm p-3 rounded-full text-white hover:bg-black/60 transition-colors\"\n aria-label=\"Next slide\"\n >\n <svg className=\"w-6 h-6\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 5l7 7-7 7\" />\n </svg>\n </button>\n </OverlaySlot>\n\n {/* Caption and controls at bottom */}\n <GradientOverlay position=\"bottom\" className=\"p-6\">\n <div className=\"space-y-3\">\n {/* Caption */}\n {state.images[state.currentIndex]?.caption && (\n <p className=\"text-white text-base\">{state.images[state.currentIndex].caption}</p>\n )}\n\n {/* Controls row */}\n <div className=\"flex items-center justify-between\">\n {/* Play/Pause autoplay */}\n <button\n onClick={controls.toggle}\n className=\"text-white hover:text-white/80 transition-colors flex items-center gap-2 text-sm\"\n >\n {state.isPaused ? (\n <>\n <svg className=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n <span>Play slideshow</span>\n </>\n ) : (\n <>\n <svg className=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M6 4h4v16H6V4zm8 0h4v16h-4V4z\" />\n </svg>\n <span>Pause slideshow</span>\n </>\n )}\n </button>\n\n {/* Dot indicators */}\n <div className=\"flex gap-2\">\n {state.images.map((_, idx) => (\n <button\n key={idx}\n onClick={() => controls.goTo(idx)}\n className={`w-2 h-2 rounded-full transition-colors ${\n idx === state.currentIndex ? 'bg-white' : 'bg-white/40 hover:bg-white/60'\n }`}\n aria-label={`Go to slide ${idx + 1}`}\n />\n ))}\n </div>\n </div>\n </div>\n </GradientOverlay>\n </>\n );\n}\n";
|
|
29
|
+
/**
|
|
30
|
+
* Slideshow Preview Entry - Tile
|
|
31
|
+
*
|
|
32
|
+
* Combined entry point for preview bundling.
|
|
33
|
+
* Wraps Slideshow around TileOverlay since tile-preview doesn't understand Next.js layouts.
|
|
34
|
+
*
|
|
35
|
+
* File path: src/app/_preview/tile.tsx
|
|
36
|
+
*/
|
|
37
|
+
export declare const slideshowPreviewTileTemplate = "'use client';\n\nimport { Slideshow, useSlideshowState, OverlaySlot, GradientOverlay, useTile } from '@thewhateverapp/tile-sdk';\n\n// Slideshow configuration injected at generation time\nconst SLIDESHOW_CONFIG = __SLIDESHOW_CONFIG__;\n\nfunction TileOverlay() {\n const tile = useTile();\n const { state } = useSlideshowState();\n\n return (\n <>\n {/* Expand button - opens full page view */}\n <OverlaySlot position=\"top-right\">\n <button\n onClick={() => tile.navigateToPage()}\n className=\"bg-black/40 backdrop-blur-sm p-2 rounded-full text-white hover:bg-black/60 transition-colors\"\n aria-label=\"Expand to full view\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4\" />\n </svg>\n </button>\n </OverlaySlot>\n\n {/* Slide counter */}\n <OverlaySlot position=\"top-left\">\n <div className=\"bg-black/50 backdrop-blur-sm px-2 py-1 rounded text-xs text-white\">\n {state.currentIndex + 1} / {state.totalSlides}\n </div>\n </OverlaySlot>\n\n {/* Caption at bottom */}\n {state.images[state.currentIndex]?.caption && (\n <GradientOverlay position=\"bottom\" className=\"p-4\">\n <p className=\"text-white text-sm\">{state.images[state.currentIndex].caption}</p>\n </GradientOverlay>\n )}\n </>\n );\n}\n\nexport default function PreviewTile() {\n return (\n <Slideshow\n images={SLIDESHOW_CONFIG.images}\n autoAdvance={SLIDESHOW_CONFIG.autoAdvance}\n intervalMs={SLIDESHOW_CONFIG.intervalMs}\n transition={SLIDESHOW_CONFIG.transition}\n showDots={true}\n showArrows={true}\n className=\"w-full h-full\"\n >\n <TileOverlay />\n </Slideshow>\n );\n}\n";
|
|
38
|
+
/**
|
|
39
|
+
* Slideshow Preview Entry - Page
|
|
40
|
+
*
|
|
41
|
+
* Combined entry point for preview bundling.
|
|
42
|
+
* Wraps Slideshow around PageOverlay since tile-preview doesn't understand Next.js layouts.
|
|
43
|
+
*
|
|
44
|
+
* File path: src/app/_preview/page.tsx
|
|
45
|
+
*/
|
|
46
|
+
export declare const slideshowPreviewPageTemplate = "'use client';\n\nimport { Slideshow, useSlideshowState, OverlaySlot, GradientOverlay } from '@thewhateverapp/tile-sdk';\n\n// Slideshow configuration injected at generation time\nconst SLIDESHOW_CONFIG = __SLIDESHOW_CONFIG__;\n\nfunction PageOverlay() {\n const { state, controls } = useSlideshowState();\n\n return (\n <>\n {/* Slide counter */}\n <OverlaySlot position=\"top-right\">\n <div className=\"bg-black/50 backdrop-blur-sm px-3 py-1.5 rounded-full text-sm text-white\">\n {state.currentIndex + 1} / {state.totalSlides}\n </div>\n </OverlaySlot>\n\n {/* Navigation arrows (larger for full page) */}\n <OverlaySlot position=\"center-left\">\n <button\n onClick={controls.prev}\n className=\"bg-black/40 backdrop-blur-sm p-3 rounded-full text-white hover:bg-black/60 transition-colors\"\n aria-label=\"Previous slide\"\n >\n <svg className=\"w-6 h-6\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M15 19l-7-7 7-7\" />\n </svg>\n </button>\n </OverlaySlot>\n\n <OverlaySlot position=\"center-right\">\n <button\n onClick={controls.next}\n className=\"bg-black/40 backdrop-blur-sm p-3 rounded-full text-white hover:bg-black/60 transition-colors\"\n aria-label=\"Next slide\"\n >\n <svg className=\"w-6 h-6\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 5l7 7-7 7\" />\n </svg>\n </button>\n </OverlaySlot>\n\n {/* Caption and controls at bottom */}\n <GradientOverlay position=\"bottom\" className=\"p-6\">\n <div className=\"space-y-3\">\n {/* Caption */}\n {state.images[state.currentIndex]?.caption && (\n <p className=\"text-white text-base\">{state.images[state.currentIndex].caption}</p>\n )}\n\n {/* Controls row */}\n <div className=\"flex items-center justify-between\">\n {/* Play/Pause autoplay */}\n <button\n onClick={controls.toggle}\n className=\"text-white hover:text-white/80 transition-colors flex items-center gap-2 text-sm\"\n >\n {state.isPaused ? (\n <>\n <svg className=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n <span>Play slideshow</span>\n </>\n ) : (\n <>\n <svg className=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M6 4h4v16H6V4zm8 0h4v16h-4V4z\" />\n </svg>\n <span>Pause slideshow</span>\n </>\n )}\n </button>\n\n {/* Dot indicators */}\n <div className=\"flex gap-2\">\n {state.images.map((_, idx) => (\n <button\n key={idx}\n onClick={() => controls.goTo(idx)}\n className={`w-2 h-2 rounded-full transition-colors ${\n idx === state.currentIndex ? 'bg-white' : 'bg-white/40 hover:bg-white/60'\n }`}\n aria-label={`Go to slide ${idx + 1}`}\n />\n ))}\n </div>\n </div>\n </div>\n </GradientOverlay>\n </>\n );\n}\n\nexport default function PreviewPage() {\n return (\n <Slideshow\n images={SLIDESHOW_CONFIG.images}\n autoAdvance={SLIDESHOW_CONFIG.autoAdvance}\n intervalMs={SLIDESHOW_CONFIG.intervalMs}\n transition={SLIDESHOW_CONFIG.transition}\n showDots={true}\n showArrows={true}\n className=\"w-full h-full\"\n >\n <PageOverlay />\n </Slideshow>\n );\n}\n";
|
|
29
47
|
//# sourceMappingURL=layout.tsx.template.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout.tsx.template.d.ts","sourceRoot":"","sources":["../../../src/templates/slideshow/layout.tsx.template.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,sqBAuBnC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,8gDAwCxC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,49GA4FxC,CAAC"}
|
|
1
|
+
{"version":3,"file":"layout.tsx.template.d.ts","sourceRoot":"","sources":["../../../src/templates/slideshow/layout.tsx.template.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,sqBAuBnC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,8gDAwCxC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,49GA4FxC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,q9DA0DxC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,+8HA+GxC,CAAC"}
|
|
@@ -181,3 +181,190 @@ export default function PageOverlay() {
|
|
|
181
181
|
);
|
|
182
182
|
}
|
|
183
183
|
`;
|
|
184
|
+
/**
|
|
185
|
+
* Slideshow Preview Entry - Tile
|
|
186
|
+
*
|
|
187
|
+
* Combined entry point for preview bundling.
|
|
188
|
+
* Wraps Slideshow around TileOverlay since tile-preview doesn't understand Next.js layouts.
|
|
189
|
+
*
|
|
190
|
+
* File path: src/app/_preview/tile.tsx
|
|
191
|
+
*/
|
|
192
|
+
export const slideshowPreviewTileTemplate = `'use client';
|
|
193
|
+
|
|
194
|
+
import { Slideshow, useSlideshowState, OverlaySlot, GradientOverlay, useTile } from '@thewhateverapp/tile-sdk';
|
|
195
|
+
|
|
196
|
+
// Slideshow configuration injected at generation time
|
|
197
|
+
const SLIDESHOW_CONFIG = __SLIDESHOW_CONFIG__;
|
|
198
|
+
|
|
199
|
+
function TileOverlay() {
|
|
200
|
+
const tile = useTile();
|
|
201
|
+
const { state } = useSlideshowState();
|
|
202
|
+
|
|
203
|
+
return (
|
|
204
|
+
<>
|
|
205
|
+
{/* Expand button - opens full page view */}
|
|
206
|
+
<OverlaySlot position="top-right">
|
|
207
|
+
<button
|
|
208
|
+
onClick={() => tile.navigateToPage()}
|
|
209
|
+
className="bg-black/40 backdrop-blur-sm p-2 rounded-full text-white hover:bg-black/60 transition-colors"
|
|
210
|
+
aria-label="Expand to full view"
|
|
211
|
+
>
|
|
212
|
+
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
213
|
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4" />
|
|
214
|
+
</svg>
|
|
215
|
+
</button>
|
|
216
|
+
</OverlaySlot>
|
|
217
|
+
|
|
218
|
+
{/* Slide counter */}
|
|
219
|
+
<OverlaySlot position="top-left">
|
|
220
|
+
<div className="bg-black/50 backdrop-blur-sm px-2 py-1 rounded text-xs text-white">
|
|
221
|
+
{state.currentIndex + 1} / {state.totalSlides}
|
|
222
|
+
</div>
|
|
223
|
+
</OverlaySlot>
|
|
224
|
+
|
|
225
|
+
{/* Caption at bottom */}
|
|
226
|
+
{state.images[state.currentIndex]?.caption && (
|
|
227
|
+
<GradientOverlay position="bottom" className="p-4">
|
|
228
|
+
<p className="text-white text-sm">{state.images[state.currentIndex].caption}</p>
|
|
229
|
+
</GradientOverlay>
|
|
230
|
+
)}
|
|
231
|
+
</>
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export default function PreviewTile() {
|
|
236
|
+
return (
|
|
237
|
+
<Slideshow
|
|
238
|
+
images={SLIDESHOW_CONFIG.images}
|
|
239
|
+
autoAdvance={SLIDESHOW_CONFIG.autoAdvance}
|
|
240
|
+
intervalMs={SLIDESHOW_CONFIG.intervalMs}
|
|
241
|
+
transition={SLIDESHOW_CONFIG.transition}
|
|
242
|
+
showDots={true}
|
|
243
|
+
showArrows={true}
|
|
244
|
+
className="w-full h-full"
|
|
245
|
+
>
|
|
246
|
+
<TileOverlay />
|
|
247
|
+
</Slideshow>
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
`;
|
|
251
|
+
/**
|
|
252
|
+
* Slideshow Preview Entry - Page
|
|
253
|
+
*
|
|
254
|
+
* Combined entry point for preview bundling.
|
|
255
|
+
* Wraps Slideshow around PageOverlay since tile-preview doesn't understand Next.js layouts.
|
|
256
|
+
*
|
|
257
|
+
* File path: src/app/_preview/page.tsx
|
|
258
|
+
*/
|
|
259
|
+
export const slideshowPreviewPageTemplate = `'use client';
|
|
260
|
+
|
|
261
|
+
import { Slideshow, useSlideshowState, OverlaySlot, GradientOverlay } from '@thewhateverapp/tile-sdk';
|
|
262
|
+
|
|
263
|
+
// Slideshow configuration injected at generation time
|
|
264
|
+
const SLIDESHOW_CONFIG = __SLIDESHOW_CONFIG__;
|
|
265
|
+
|
|
266
|
+
function PageOverlay() {
|
|
267
|
+
const { state, controls } = useSlideshowState();
|
|
268
|
+
|
|
269
|
+
return (
|
|
270
|
+
<>
|
|
271
|
+
{/* Slide counter */}
|
|
272
|
+
<OverlaySlot position="top-right">
|
|
273
|
+
<div className="bg-black/50 backdrop-blur-sm px-3 py-1.5 rounded-full text-sm text-white">
|
|
274
|
+
{state.currentIndex + 1} / {state.totalSlides}
|
|
275
|
+
</div>
|
|
276
|
+
</OverlaySlot>
|
|
277
|
+
|
|
278
|
+
{/* Navigation arrows (larger for full page) */}
|
|
279
|
+
<OverlaySlot position="center-left">
|
|
280
|
+
<button
|
|
281
|
+
onClick={controls.prev}
|
|
282
|
+
className="bg-black/40 backdrop-blur-sm p-3 rounded-full text-white hover:bg-black/60 transition-colors"
|
|
283
|
+
aria-label="Previous slide"
|
|
284
|
+
>
|
|
285
|
+
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
286
|
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
|
|
287
|
+
</svg>
|
|
288
|
+
</button>
|
|
289
|
+
</OverlaySlot>
|
|
290
|
+
|
|
291
|
+
<OverlaySlot position="center-right">
|
|
292
|
+
<button
|
|
293
|
+
onClick={controls.next}
|
|
294
|
+
className="bg-black/40 backdrop-blur-sm p-3 rounded-full text-white hover:bg-black/60 transition-colors"
|
|
295
|
+
aria-label="Next slide"
|
|
296
|
+
>
|
|
297
|
+
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
298
|
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
|
|
299
|
+
</svg>
|
|
300
|
+
</button>
|
|
301
|
+
</OverlaySlot>
|
|
302
|
+
|
|
303
|
+
{/* Caption and controls at bottom */}
|
|
304
|
+
<GradientOverlay position="bottom" className="p-6">
|
|
305
|
+
<div className="space-y-3">
|
|
306
|
+
{/* Caption */}
|
|
307
|
+
{state.images[state.currentIndex]?.caption && (
|
|
308
|
+
<p className="text-white text-base">{state.images[state.currentIndex].caption}</p>
|
|
309
|
+
)}
|
|
310
|
+
|
|
311
|
+
{/* Controls row */}
|
|
312
|
+
<div className="flex items-center justify-between">
|
|
313
|
+
{/* Play/Pause autoplay */}
|
|
314
|
+
<button
|
|
315
|
+
onClick={controls.toggle}
|
|
316
|
+
className="text-white hover:text-white/80 transition-colors flex items-center gap-2 text-sm"
|
|
317
|
+
>
|
|
318
|
+
{state.isPaused ? (
|
|
319
|
+
<>
|
|
320
|
+
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
|
321
|
+
<path d="M8 5v14l11-7z" />
|
|
322
|
+
</svg>
|
|
323
|
+
<span>Play slideshow</span>
|
|
324
|
+
</>
|
|
325
|
+
) : (
|
|
326
|
+
<>
|
|
327
|
+
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
|
328
|
+
<path d="M6 4h4v16H6V4zm8 0h4v16h-4V4z" />
|
|
329
|
+
</svg>
|
|
330
|
+
<span>Pause slideshow</span>
|
|
331
|
+
</>
|
|
332
|
+
)}
|
|
333
|
+
</button>
|
|
334
|
+
|
|
335
|
+
{/* Dot indicators */}
|
|
336
|
+
<div className="flex gap-2">
|
|
337
|
+
{state.images.map((_, idx) => (
|
|
338
|
+
<button
|
|
339
|
+
key={idx}
|
|
340
|
+
onClick={() => controls.goTo(idx)}
|
|
341
|
+
className={\`w-2 h-2 rounded-full transition-colors \${
|
|
342
|
+
idx === state.currentIndex ? 'bg-white' : 'bg-white/40 hover:bg-white/60'
|
|
343
|
+
}\`}
|
|
344
|
+
aria-label={\`Go to slide \${idx + 1}\`}
|
|
345
|
+
/>
|
|
346
|
+
))}
|
|
347
|
+
</div>
|
|
348
|
+
</div>
|
|
349
|
+
</div>
|
|
350
|
+
</GradientOverlay>
|
|
351
|
+
</>
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
export default function PreviewPage() {
|
|
356
|
+
return (
|
|
357
|
+
<Slideshow
|
|
358
|
+
images={SLIDESHOW_CONFIG.images}
|
|
359
|
+
autoAdvance={SLIDESHOW_CONFIG.autoAdvance}
|
|
360
|
+
intervalMs={SLIDESHOW_CONFIG.intervalMs}
|
|
361
|
+
transition={SLIDESHOW_CONFIG.transition}
|
|
362
|
+
showDots={true}
|
|
363
|
+
showArrows={true}
|
|
364
|
+
className="w-full h-full"
|
|
365
|
+
>
|
|
366
|
+
<PageOverlay />
|
|
367
|
+
</Slideshow>
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
`;
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* - Tile and page routes only render overlay content
|
|
10
10
|
* - This ensures seamless video persistence across navigation
|
|
11
11
|
*/
|
|
12
|
-
export { videoLayoutTemplate, videoTileOverlayTemplate, videoPageOverlayTemplate, } from './layout.tsx.template.js';
|
|
12
|
+
export { videoLayoutTemplate, videoTileOverlayTemplate, videoPageOverlayTemplate, videoPreviewTileTemplate, videoPreviewPageTemplate, } from './layout.tsx.template.js';
|
|
13
13
|
export { videoManagerTemplate } from './VideoManager.ts.template.js';
|
|
14
14
|
export { persistentVideoTemplate } from './PersistentVideo.tsx.template.js';
|
|
15
15
|
/**
|
|
@@ -21,6 +21,14 @@ export declare const videoTemplateFiles: {
|
|
|
21
21
|
'src/app/(video)/tile/page.tsx': string;
|
|
22
22
|
'src/app/(video)/page/page.tsx': string;
|
|
23
23
|
};
|
|
24
|
+
/**
|
|
25
|
+
* Preview entry files for tile-preview bundling.
|
|
26
|
+
* These combine VideoPlayer + overlay since tile-preview doesn't understand Next.js layouts.
|
|
27
|
+
*/
|
|
28
|
+
export declare const videoPreviewFiles: {
|
|
29
|
+
'src/app/_preview/tile.tsx': string;
|
|
30
|
+
'src/app/_preview/page.tsx': string;
|
|
31
|
+
};
|
|
24
32
|
export declare const videoLegacyTemplateFiles: {
|
|
25
33
|
'src/shared/lib/VideoManager.ts': string;
|
|
26
34
|
'src/shared/components/PersistentVideo.tsx': string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/video/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAE5E;;;GAGG;AACH,eAAO,MAAM,kBAAkB;;;;CAM9B,CAAC;AAGF,eAAO,MAAM,wBAAwB;;;CAGpC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/video/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACxB,wBAAwB,EACxB,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAE5E;;;GAGG;AACH,eAAO,MAAM,kBAAkB;;;;CAM9B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,iBAAiB;;;CAG7B,CAAC;AAGF,eAAO,MAAM,wBAAwB;;;CAGpC,CAAC"}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* - This ensures seamless video persistence across navigation
|
|
11
11
|
*/
|
|
12
12
|
// ESM requires explicit .js extension for imports
|
|
13
|
-
export { videoLayoutTemplate, videoTileOverlayTemplate, videoPageOverlayTemplate, } from './layout.tsx.template.js';
|
|
13
|
+
export { videoLayoutTemplate, videoTileOverlayTemplate, videoPageOverlayTemplate, videoPreviewTileTemplate, videoPreviewPageTemplate, } from './layout.tsx.template.js';
|
|
14
14
|
// Legacy templates (kept for backwards compatibility)
|
|
15
15
|
export { videoManagerTemplate } from './VideoManager.ts.template.js';
|
|
16
16
|
export { persistentVideoTemplate } from './PersistentVideo.tsx.template.js';
|
|
@@ -19,12 +19,20 @@ export { persistentVideoTemplate } from './PersistentVideo.tsx.template.js';
|
|
|
19
19
|
* The (video) route group ensures VideoPlayer persists across tile/page navigation.
|
|
20
20
|
*/
|
|
21
21
|
export const videoTemplateFiles = {
|
|
22
|
-
// Layout mounts VideoPlayer once
|
|
22
|
+
// Layout mounts VideoPlayer once (for production - Next.js applies this)
|
|
23
23
|
'src/app/(video)/layout.tsx': 'videoLayoutTemplate',
|
|
24
|
-
// Overlay-only pages (no VideoPlayer wrapper needed)
|
|
24
|
+
// Overlay-only pages (no VideoPlayer wrapper needed in production)
|
|
25
25
|
'src/app/(video)/tile/page.tsx': 'videoTileOverlayTemplate',
|
|
26
26
|
'src/app/(video)/page/page.tsx': 'videoPageOverlayTemplate',
|
|
27
27
|
};
|
|
28
|
+
/**
|
|
29
|
+
* Preview entry files for tile-preview bundling.
|
|
30
|
+
* These combine VideoPlayer + overlay since tile-preview doesn't understand Next.js layouts.
|
|
31
|
+
*/
|
|
32
|
+
export const videoPreviewFiles = {
|
|
33
|
+
'src/app/_preview/tile.tsx': 'videoPreviewTileTemplate',
|
|
34
|
+
'src/app/_preview/page.tsx': 'videoPreviewPageTemplate',
|
|
35
|
+
};
|
|
28
36
|
// Legacy file structure (deprecated)
|
|
29
37
|
export const videoLegacyTemplateFiles = {
|
|
30
38
|
'src/shared/lib/VideoManager.ts': 'videoManagerTemplate',
|
|
@@ -26,4 +26,22 @@ export declare const videoTileOverlayTemplate = "'use client';\n\nimport { useVi
|
|
|
26
26
|
* File path: src/app/(video)/page/page.tsx
|
|
27
27
|
*/
|
|
28
28
|
export declare const videoPageOverlayTemplate = "'use client';\n\nimport { useVideoState, OverlaySlot, GradientOverlay } from '@thewhateverapp/tile-sdk';\n\nfunction formatTime(seconds: number): string {\n if (!seconds || !isFinite(seconds)) return '0:00';\n const mins = Math.floor(seconds / 60);\n const secs = Math.floor(seconds % 60);\n return `${mins}:${secs.toString().padStart(2, '0')}`;\n}\n\nexport default function PageOverlay() {\n const { state, controls } = useVideoState();\n\n return (\n <>\n {/* Play/Pause button in center when paused */}\n {!state.isPlaying && !state.isLoading && (\n <OverlaySlot position=\"center\">\n <button\n onClick={controls.play}\n className=\"w-20 h-20 bg-white/20 backdrop-blur-sm rounded-full flex items-center justify-center hover:bg-white/30 transition-colors\"\n >\n <svg className=\"w-10 h-10 text-white ml-1\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n </button>\n </OverlaySlot>\n )}\n\n {/* Bottom gradient with controls */}\n <GradientOverlay position=\"bottom\" className=\"p-6\">\n <div className=\"space-y-3\">\n {/* Progress bar */}\n <div\n className=\"h-1.5 bg-white/30 rounded-full overflow-hidden cursor-pointer\"\n onClick={(e) => {\n const rect = e.currentTarget.getBoundingClientRect();\n const percent = (e.clientX - rect.left) / rect.width;\n controls.seek(percent * state.duration);\n }}\n >\n <div\n className=\"h-full bg-white rounded-full transition-all duration-200\"\n style={{ width: `${(state.currentTime / state.duration) * 100 || 0}%` }}\n />\n </div>\n\n {/* Controls row */}\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n {/* Play/Pause */}\n <button\n onClick={controls.toggle}\n className=\"text-white hover:text-white/80 transition-colors\"\n >\n {state.isPlaying ? (\n <svg className=\"w-6 h-6\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M6 4h4v16H6V4zm8 0h4v16h-4V4z\" />\n </svg>\n ) : (\n <svg className=\"w-6 h-6\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n )}\n </button>\n\n {/* Mute toggle */}\n <button\n onClick={() => controls.setMuted(!state.muted)}\n className=\"text-white hover:text-white/80 transition-colors\"\n >\n {state.muted ? (\n <svg className=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z\" />\n </svg>\n ) : (\n <svg className=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z\" />\n </svg>\n )}\n </button>\n\n {/* Time display */}\n <span className=\"text-sm text-white/80\">\n {formatTime(state.currentTime)} / {formatTime(state.duration)}\n </span>\n </div>\n </div>\n </div>\n </GradientOverlay>\n </>\n );\n}\n";
|
|
29
|
+
/**
|
|
30
|
+
* Video Preview Entry - Tile
|
|
31
|
+
*
|
|
32
|
+
* Combined entry point for preview bundling.
|
|
33
|
+
* Wraps VideoPlayer around TileOverlay since tile-preview doesn't understand Next.js layouts.
|
|
34
|
+
*
|
|
35
|
+
* File path: src/app/_preview/tile.tsx
|
|
36
|
+
*/
|
|
37
|
+
export declare const videoPreviewTileTemplate = "'use client';\n\nimport { VideoPlayer, useVideoState, OverlaySlot, GradientOverlay, useTile } from '@thewhateverapp/tile-sdk';\n\nfunction formatTime(seconds: number): string {\n if (!seconds || !isFinite(seconds)) return '0:00';\n const mins = Math.floor(seconds / 60);\n const secs = Math.floor(seconds % 60);\n return `${mins}:${secs.toString().padStart(2, '0')}`;\n}\n\nfunction TileOverlay() {\n const tile = useTile();\n const { state, controls } = useVideoState();\n\n return (\n <>\n {/* Expand button - opens full page view */}\n <OverlaySlot position=\"top-right\">\n <button\n onClick={() => tile.navigateToPage()}\n className=\"bg-black/40 backdrop-blur-sm p-2 rounded-full text-white hover:bg-black/60 transition-colors\"\n aria-label=\"Expand to full view\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4\" />\n </svg>\n </button>\n </OverlaySlot>\n\n {/* Play/Pause button in center when paused */}\n {!state.isPlaying && !state.isLoading && (\n <OverlaySlot position=\"center\">\n <button\n onClick={controls.play}\n className=\"w-16 h-16 bg-white/20 backdrop-blur-sm rounded-full flex items-center justify-center hover:bg-white/30 transition-colors\"\n >\n <svg className=\"w-8 h-8 text-white ml-1\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n </button>\n </OverlaySlot>\n )}\n\n {/* Bottom gradient with progress */}\n <GradientOverlay position=\"bottom\" className=\"p-4\">\n <div className=\"space-y-2\">\n {/* Progress bar */}\n <div className=\"h-1 bg-white/30 rounded-full overflow-hidden\">\n <div\n className=\"h-full bg-white rounded-full transition-all duration-200\"\n style={{ width: `${(state.currentTime / state.duration) * 100 || 0}%` }}\n />\n </div>\n {/* Time display */}\n <div className=\"flex justify-between text-xs text-white/80\">\n <span>{formatTime(state.currentTime)}</span>\n <span>{formatTime(state.duration)}</span>\n </div>\n </div>\n </GradientOverlay>\n </>\n );\n}\n\nexport default function PreviewTile() {\n return (\n <VideoPlayer className=\"w-full h-full\">\n <TileOverlay />\n </VideoPlayer>\n );\n}\n";
|
|
38
|
+
/**
|
|
39
|
+
* Video Preview Entry - Page
|
|
40
|
+
*
|
|
41
|
+
* Combined entry point for preview bundling.
|
|
42
|
+
* Wraps VideoPlayer around PageOverlay since tile-preview doesn't understand Next.js layouts.
|
|
43
|
+
*
|
|
44
|
+
* File path: src/app/_preview/page.tsx
|
|
45
|
+
*/
|
|
46
|
+
export declare const videoPreviewPageTemplate = "'use client';\n\nimport { VideoPlayer, useVideoState, OverlaySlot, GradientOverlay } from '@thewhateverapp/tile-sdk';\n\nfunction formatTime(seconds: number): string {\n if (!seconds || !isFinite(seconds)) return '0:00';\n const mins = Math.floor(seconds / 60);\n const secs = Math.floor(seconds % 60);\n return `${mins}:${secs.toString().padStart(2, '0')}`;\n}\n\nfunction PageOverlay() {\n const { state, controls } = useVideoState();\n\n return (\n <>\n {/* Play/Pause button in center when paused */}\n {!state.isPlaying && !state.isLoading && (\n <OverlaySlot position=\"center\">\n <button\n onClick={controls.play}\n className=\"w-20 h-20 bg-white/20 backdrop-blur-sm rounded-full flex items-center justify-center hover:bg-white/30 transition-colors\"\n >\n <svg className=\"w-10 h-10 text-white ml-1\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n </button>\n </OverlaySlot>\n )}\n\n {/* Bottom gradient with controls */}\n <GradientOverlay position=\"bottom\" className=\"p-6\">\n <div className=\"space-y-3\">\n {/* Progress bar */}\n <div\n className=\"h-1.5 bg-white/30 rounded-full overflow-hidden cursor-pointer\"\n onClick={(e) => {\n const rect = e.currentTarget.getBoundingClientRect();\n const percent = (e.clientX - rect.left) / rect.width;\n controls.seek(percent * state.duration);\n }}\n >\n <div\n className=\"h-full bg-white rounded-full transition-all duration-200\"\n style={{ width: `${(state.currentTime / state.duration) * 100 || 0}%` }}\n />\n </div>\n\n {/* Controls row */}\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n {/* Play/Pause */}\n <button\n onClick={controls.toggle}\n className=\"text-white hover:text-white/80 transition-colors\"\n >\n {state.isPlaying ? (\n <svg className=\"w-6 h-6\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M6 4h4v16H6V4zm8 0h4v16h-4V4z\" />\n </svg>\n ) : (\n <svg className=\"w-6 h-6\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n )}\n </button>\n\n {/* Mute toggle */}\n <button\n onClick={() => controls.setMuted(!state.muted)}\n className=\"text-white hover:text-white/80 transition-colors\"\n >\n {state.muted ? (\n <svg className=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z\" />\n </svg>\n ) : (\n <svg className=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z\" />\n </svg>\n )}\n </button>\n\n {/* Time display */}\n <span className=\"text-sm text-white/80\">\n {formatTime(state.currentTime)} / {formatTime(state.duration)}\n </span>\n </div>\n </div>\n </div>\n </GradientOverlay>\n </>\n );\n}\n\nexport default function PreviewPage() {\n return (\n <VideoPlayer className=\"w-full h-full\">\n <PageOverlay />\n </VideoPlayer>\n );\n}\n";
|
|
29
47
|
//# sourceMappingURL=layout.tsx.template.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout.tsx.template.d.ts","sourceRoot":"","sources":["../../../src/templates/video/layout.tsx.template.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,uUAY/B,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,qiFAiEpC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,qgIA8FpC,CAAC"}
|
|
1
|
+
{"version":3,"file":"layout.tsx.template.d.ts","sourceRoot":"","sources":["../../../src/templates/video/layout.tsx.template.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,uUAY/B,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,qiFAiEpC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,qgIA8FpC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,ipFAwEpC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,6pIAsGpC,CAAC"}
|
|
@@ -197,3 +197,195 @@ export default function PageOverlay() {
|
|
|
197
197
|
);
|
|
198
198
|
}
|
|
199
199
|
`;
|
|
200
|
+
/**
|
|
201
|
+
* Video Preview Entry - Tile
|
|
202
|
+
*
|
|
203
|
+
* Combined entry point for preview bundling.
|
|
204
|
+
* Wraps VideoPlayer around TileOverlay since tile-preview doesn't understand Next.js layouts.
|
|
205
|
+
*
|
|
206
|
+
* File path: src/app/_preview/tile.tsx
|
|
207
|
+
*/
|
|
208
|
+
export const videoPreviewTileTemplate = `'use client';
|
|
209
|
+
|
|
210
|
+
import { VideoPlayer, useVideoState, OverlaySlot, GradientOverlay, useTile } from '@thewhateverapp/tile-sdk';
|
|
211
|
+
|
|
212
|
+
function formatTime(seconds: number): string {
|
|
213
|
+
if (!seconds || !isFinite(seconds)) return '0:00';
|
|
214
|
+
const mins = Math.floor(seconds / 60);
|
|
215
|
+
const secs = Math.floor(seconds % 60);
|
|
216
|
+
return \`\${mins}:\${secs.toString().padStart(2, '0')}\`;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function TileOverlay() {
|
|
220
|
+
const tile = useTile();
|
|
221
|
+
const { state, controls } = useVideoState();
|
|
222
|
+
|
|
223
|
+
return (
|
|
224
|
+
<>
|
|
225
|
+
{/* Expand button - opens full page view */}
|
|
226
|
+
<OverlaySlot position="top-right">
|
|
227
|
+
<button
|
|
228
|
+
onClick={() => tile.navigateToPage()}
|
|
229
|
+
className="bg-black/40 backdrop-blur-sm p-2 rounded-full text-white hover:bg-black/60 transition-colors"
|
|
230
|
+
aria-label="Expand to full view"
|
|
231
|
+
>
|
|
232
|
+
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
233
|
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4" />
|
|
234
|
+
</svg>
|
|
235
|
+
</button>
|
|
236
|
+
</OverlaySlot>
|
|
237
|
+
|
|
238
|
+
{/* Play/Pause button in center when paused */}
|
|
239
|
+
{!state.isPlaying && !state.isLoading && (
|
|
240
|
+
<OverlaySlot position="center">
|
|
241
|
+
<button
|
|
242
|
+
onClick={controls.play}
|
|
243
|
+
className="w-16 h-16 bg-white/20 backdrop-blur-sm rounded-full flex items-center justify-center hover:bg-white/30 transition-colors"
|
|
244
|
+
>
|
|
245
|
+
<svg className="w-8 h-8 text-white ml-1" fill="currentColor" viewBox="0 0 24 24">
|
|
246
|
+
<path d="M8 5v14l11-7z" />
|
|
247
|
+
</svg>
|
|
248
|
+
</button>
|
|
249
|
+
</OverlaySlot>
|
|
250
|
+
)}
|
|
251
|
+
|
|
252
|
+
{/* Bottom gradient with progress */}
|
|
253
|
+
<GradientOverlay position="bottom" className="p-4">
|
|
254
|
+
<div className="space-y-2">
|
|
255
|
+
{/* Progress bar */}
|
|
256
|
+
<div className="h-1 bg-white/30 rounded-full overflow-hidden">
|
|
257
|
+
<div
|
|
258
|
+
className="h-full bg-white rounded-full transition-all duration-200"
|
|
259
|
+
style={{ width: \`\${(state.currentTime / state.duration) * 100 || 0}%\` }}
|
|
260
|
+
/>
|
|
261
|
+
</div>
|
|
262
|
+
{/* Time display */}
|
|
263
|
+
<div className="flex justify-between text-xs text-white/80">
|
|
264
|
+
<span>{formatTime(state.currentTime)}</span>
|
|
265
|
+
<span>{formatTime(state.duration)}</span>
|
|
266
|
+
</div>
|
|
267
|
+
</div>
|
|
268
|
+
</GradientOverlay>
|
|
269
|
+
</>
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export default function PreviewTile() {
|
|
274
|
+
return (
|
|
275
|
+
<VideoPlayer className="w-full h-full">
|
|
276
|
+
<TileOverlay />
|
|
277
|
+
</VideoPlayer>
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
`;
|
|
281
|
+
/**
|
|
282
|
+
* Video Preview Entry - Page
|
|
283
|
+
*
|
|
284
|
+
* Combined entry point for preview bundling.
|
|
285
|
+
* Wraps VideoPlayer around PageOverlay since tile-preview doesn't understand Next.js layouts.
|
|
286
|
+
*
|
|
287
|
+
* File path: src/app/_preview/page.tsx
|
|
288
|
+
*/
|
|
289
|
+
export const videoPreviewPageTemplate = `'use client';
|
|
290
|
+
|
|
291
|
+
import { VideoPlayer, useVideoState, OverlaySlot, GradientOverlay } from '@thewhateverapp/tile-sdk';
|
|
292
|
+
|
|
293
|
+
function formatTime(seconds: number): string {
|
|
294
|
+
if (!seconds || !isFinite(seconds)) return '0:00';
|
|
295
|
+
const mins = Math.floor(seconds / 60);
|
|
296
|
+
const secs = Math.floor(seconds % 60);
|
|
297
|
+
return \`\${mins}:\${secs.toString().padStart(2, '0')}\`;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function PageOverlay() {
|
|
301
|
+
const { state, controls } = useVideoState();
|
|
302
|
+
|
|
303
|
+
return (
|
|
304
|
+
<>
|
|
305
|
+
{/* Play/Pause button in center when paused */}
|
|
306
|
+
{!state.isPlaying && !state.isLoading && (
|
|
307
|
+
<OverlaySlot position="center">
|
|
308
|
+
<button
|
|
309
|
+
onClick={controls.play}
|
|
310
|
+
className="w-20 h-20 bg-white/20 backdrop-blur-sm rounded-full flex items-center justify-center hover:bg-white/30 transition-colors"
|
|
311
|
+
>
|
|
312
|
+
<svg className="w-10 h-10 text-white ml-1" fill="currentColor" viewBox="0 0 24 24">
|
|
313
|
+
<path d="M8 5v14l11-7z" />
|
|
314
|
+
</svg>
|
|
315
|
+
</button>
|
|
316
|
+
</OverlaySlot>
|
|
317
|
+
)}
|
|
318
|
+
|
|
319
|
+
{/* Bottom gradient with controls */}
|
|
320
|
+
<GradientOverlay position="bottom" className="p-6">
|
|
321
|
+
<div className="space-y-3">
|
|
322
|
+
{/* Progress bar */}
|
|
323
|
+
<div
|
|
324
|
+
className="h-1.5 bg-white/30 rounded-full overflow-hidden cursor-pointer"
|
|
325
|
+
onClick={(e) => {
|
|
326
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
327
|
+
const percent = (e.clientX - rect.left) / rect.width;
|
|
328
|
+
controls.seek(percent * state.duration);
|
|
329
|
+
}}
|
|
330
|
+
>
|
|
331
|
+
<div
|
|
332
|
+
className="h-full bg-white rounded-full transition-all duration-200"
|
|
333
|
+
style={{ width: \`\${(state.currentTime / state.duration) * 100 || 0}%\` }}
|
|
334
|
+
/>
|
|
335
|
+
</div>
|
|
336
|
+
|
|
337
|
+
{/* Controls row */}
|
|
338
|
+
<div className="flex items-center justify-between">
|
|
339
|
+
<div className="flex items-center gap-4">
|
|
340
|
+
{/* Play/Pause */}
|
|
341
|
+
<button
|
|
342
|
+
onClick={controls.toggle}
|
|
343
|
+
className="text-white hover:text-white/80 transition-colors"
|
|
344
|
+
>
|
|
345
|
+
{state.isPlaying ? (
|
|
346
|
+
<svg className="w-6 h-6" fill="currentColor" viewBox="0 0 24 24">
|
|
347
|
+
<path d="M6 4h4v16H6V4zm8 0h4v16h-4V4z" />
|
|
348
|
+
</svg>
|
|
349
|
+
) : (
|
|
350
|
+
<svg className="w-6 h-6" fill="currentColor" viewBox="0 0 24 24">
|
|
351
|
+
<path d="M8 5v14l11-7z" />
|
|
352
|
+
</svg>
|
|
353
|
+
)}
|
|
354
|
+
</button>
|
|
355
|
+
|
|
356
|
+
{/* Mute toggle */}
|
|
357
|
+
<button
|
|
358
|
+
onClick={() => controls.setMuted(!state.muted)}
|
|
359
|
+
className="text-white hover:text-white/80 transition-colors"
|
|
360
|
+
>
|
|
361
|
+
{state.muted ? (
|
|
362
|
+
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
|
363
|
+
<path d="M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z" />
|
|
364
|
+
</svg>
|
|
365
|
+
) : (
|
|
366
|
+
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
|
367
|
+
<path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z" />
|
|
368
|
+
</svg>
|
|
369
|
+
)}
|
|
370
|
+
</button>
|
|
371
|
+
|
|
372
|
+
{/* Time display */}
|
|
373
|
+
<span className="text-sm text-white/80">
|
|
374
|
+
{formatTime(state.currentTime)} / {formatTime(state.duration)}
|
|
375
|
+
</span>
|
|
376
|
+
</div>
|
|
377
|
+
</div>
|
|
378
|
+
</div>
|
|
379
|
+
</GradientOverlay>
|
|
380
|
+
</>
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
export default function PreviewPage() {
|
|
385
|
+
return (
|
|
386
|
+
<VideoPlayer className="w-full h-full">
|
|
387
|
+
<PageOverlay />
|
|
388
|
+
</VideoPlayer>
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
`;
|