@thewhateverapp/tile-sdk 0.17.16 → 0.18.0
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/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/templates/slideshow/layout.tsx.template.d.ts +3 -3
- package/dist/templates/slideshow/layout.tsx.template.d.ts.map +1 -1
- package/dist/templates/slideshow/layout.tsx.template.js +42 -36
- package/dist/templates/video/layout.tsx.template.d.ts +3 -3
- package/dist/templates/video/layout.tsx.template.d.ts.map +1 -1
- package/dist/templates/video/layout.tsx.template.js +19 -13
- package/package.json +1 -21
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export { TileProvider } from './react/TileProvider.js';
|
|
1
|
+
export { TileProvider, TileContext } from './react/TileProvider.js';
|
|
2
|
+
export type { TileContextValue } from './react/TileProvider.js';
|
|
2
3
|
export { useTile } from './react/useTile.js';
|
|
3
4
|
export { useTileNavigation } from './react/useTileNavigation.js';
|
|
4
5
|
export { useKeyboard } from './react/useKeyboard.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACpE,YAAY,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAG/C,OAAO,EAEL,WAAW,EACX,aAAa,EACb,QAAQ,EAAE,0BAA0B;AACpC,WAAW,EACX,YAAY,EACZ,gBAAgB,EAEhB,SAAS,EACT,iBAAiB,EACjB,YAAY,EAAE,8BAA8B;AAE5C,WAAW,EACX,WAAW,EACX,eAAe,GAChB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EAEV,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,QAAQ,EAER,UAAU,EACV,cAAc,EACd,iBAAiB,EACjB,qBAAqB,EACrB,cAAc,EAEd,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAG3D,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACnE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGrH,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAGtE,cAAc,kBAAkB,CAAC;AAGjC,cAAc,YAAY,CAAC;AAG3B,cAAc,sBAAsB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// React components and hooks
|
|
2
|
-
export { TileProvider } from './react/TileProvider.js';
|
|
2
|
+
export { TileProvider, TileContext } from './react/TileProvider.js';
|
|
3
3
|
export { useTile } from './react/useTile.js';
|
|
4
4
|
export { useTileNavigation } from './react/useTileNavigation.js';
|
|
5
5
|
export { useKeyboard } from './react/useKeyboard.js';
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*
|
|
18
18
|
* File path: src/app/(slideshow)/layout.tsx
|
|
19
19
|
*/
|
|
20
|
-
export declare const slideshowLayoutTemplate = "'use client';\n\nimport { Slideshow } from '@thewhateverapp/tile-sdk';\n\n// Slideshow configuration injected at generation time\nconst SLIDESHOW_CONFIG = __SLIDESHOW_CONFIG__;\n\nexport default function SlideshowLayout({ children }: { children: React.ReactNode }) {\n return (\n <Slideshow\n
|
|
20
|
+
export declare const slideshowLayoutTemplate = "'use client';\n\nimport { Slideshow, TileProvider } from '@thewhateverapp/tile-sdk';\n\n// Slideshow configuration injected at generation time\nconst SLIDESHOW_CONFIG = __SLIDESHOW_CONFIG__;\n\nexport default function SlideshowLayout({ children }: { children: React.ReactNode }) {\n return (\n <TileProvider>\n <Slideshow\n images={SLIDESHOW_CONFIG.images}\n autoAdvance={SLIDESHOW_CONFIG.autoAdvance}\n intervalMs={SLIDESHOW_CONFIG.intervalMs}\n transition={SLIDESHOW_CONFIG.transition}\n showDots={false}\n showArrows={false}\n className=\"w-full h-full\"\n >\n {/* Children are the route-specific overlays */}\n {children}\n </Slideshow>\n </TileProvider>\n );\n}\n";
|
|
21
21
|
/**
|
|
22
22
|
* Slideshow Tile Overlay Template
|
|
23
23
|
*
|
|
@@ -44,7 +44,7 @@ export declare const slideshowPageOverlayTemplate = "'use client';\n\nimport { u
|
|
|
44
44
|
*
|
|
45
45
|
* File path: src/app/_preview/tile.tsx
|
|
46
46
|
*/
|
|
47
|
-
export declare const slideshowPreviewTileTemplate = "'use client';\n\nimport { Slideshow, useSlideshowState, 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, controls } = useSlideshowState();\n\n return (\n <>\n <div className=\"absolute top-3 right-3 z-20 pointer-events-auto\">\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-5 h-5\" 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 </div>\n\n {state.totalSlides > 1 && (\n <div className=\"absolute top-3 left-3 z-10 pointer-events-none\">\n <div className=\"bg-black/50 backdrop-blur-sm px-2 py-1 rounded text-xs text-white font-medium\">\n {state.currentIndex + 1} / {state.totalSlides}\n </div>\n </div>\n )}\n\n {state.totalSlides > 1 && (\n <div className=\"absolute bottom-3 left-1/2 -translate-x-1/2 z-20 pointer-events-auto\">\n <div className=\"flex gap-1.5\">\n {state.images.map((_, index) => (\n <button\n key={index}\n onClick={() => controls.goTo(index)}\n disabled={state.isTransitioning}\n className={`w-2 h-2 rounded-full transition-colors ${\n index === state.currentIndex\n ? 'bg-white'\n : 'bg-white/40 hover:bg-white/60'\n }`}\n aria-label={`Go to slide ${index + 1}`}\n />\n ))}\n </div>\n </div>\n )}\n\n {state.images[state.currentIndex]?.caption && (\n <div className=\"absolute bottom-10 left-3 right-3 z-10 pointer-events-none\">\n <div className=\"bg-black/50 backdrop-blur-sm px-3 py-2 rounded text-white text-sm\">\n {state.images[state.currentIndex].caption}\n </div>\n </div>\n )}\n </>\n );\n}\n\nexport default function PreviewTile() {\n return (\n <Slideshow\n
|
|
47
|
+
export declare const slideshowPreviewTileTemplate = "'use client';\n\nimport { Slideshow, TileProvider, useSlideshowState, 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, controls } = useSlideshowState();\n\n return (\n <>\n <div className=\"absolute top-3 right-3 z-20 pointer-events-auto\">\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-5 h-5\" 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 </div>\n\n {state.totalSlides > 1 && (\n <div className=\"absolute top-3 left-3 z-10 pointer-events-none\">\n <div className=\"bg-black/50 backdrop-blur-sm px-2 py-1 rounded text-xs text-white font-medium\">\n {state.currentIndex + 1} / {state.totalSlides}\n </div>\n </div>\n )}\n\n {state.totalSlides > 1 && (\n <div className=\"absolute bottom-3 left-1/2 -translate-x-1/2 z-20 pointer-events-auto\">\n <div className=\"flex gap-1.5\">\n {state.images.map((_, index) => (\n <button\n key={index}\n onClick={() => controls.goTo(index)}\n disabled={state.isTransitioning}\n className={`w-2 h-2 rounded-full transition-colors ${\n index === state.currentIndex\n ? 'bg-white'\n : 'bg-white/40 hover:bg-white/60'\n }`}\n aria-label={`Go to slide ${index + 1}`}\n />\n ))}\n </div>\n </div>\n )}\n\n {state.images[state.currentIndex]?.caption && (\n <div className=\"absolute bottom-10 left-3 right-3 z-10 pointer-events-none\">\n <div className=\"bg-black/50 backdrop-blur-sm px-3 py-2 rounded text-white text-sm\">\n {state.images[state.currentIndex].caption}\n </div>\n </div>\n )}\n </>\n );\n}\n\nexport default function PreviewTile() {\n return (\n <TileProvider>\n <Slideshow\n images={SLIDESHOW_CONFIG.images}\n autoAdvance={SLIDESHOW_CONFIG.autoAdvance}\n intervalMs={SLIDESHOW_CONFIG.intervalMs}\n transition={SLIDESHOW_CONFIG.transition}\n showDots={false}\n showArrows={false}\n className=\"w-full h-full\"\n >\n <TileOverlay />\n </Slideshow>\n </TileProvider>\n );\n}\n";
|
|
48
48
|
/**
|
|
49
49
|
* Slideshow Preview Entry - Page
|
|
50
50
|
*
|
|
@@ -53,5 +53,5 @@ export declare const slideshowPreviewTileTemplate = "'use client';\n\nimport { S
|
|
|
53
53
|
*
|
|
54
54
|
* File path: src/app/_preview/page.tsx
|
|
55
55
|
*/
|
|
56
|
-
export declare const slideshowPreviewPageTemplate = "'use client';\n\nimport { Slideshow, useSlideshowState, useTile } from '@thewhateverapp/tile-sdk';\nimport { useState, useEffect, useCallback } from 'react';\n\n// Slideshow configuration injected at generation time\nconst SLIDESHOW_CONFIG = __SLIDESHOW_CONFIG__;\n\nfunction PageOverlay() {\n const tile = useTile();\n const { state, controls } = useSlideshowState();\n const [showControls, setShowControls] = useState(true);\n const [hideTimeout, setHideTimeout] = useState<NodeJS.Timeout | null>(null);\n\n const resetHideTimer = useCallback(() => {\n if (hideTimeout) {\n clearTimeout(hideTimeout);\n }\n setShowControls(true);\n\n if (!state.isPaused) {\n const timeout = setTimeout(() => {\n setShowControls(false);\n }, 3000);\n setHideTimeout(timeout);\n }\n }, [state.isPaused, hideTimeout]);\n\n useEffect(() => {\n if (state.isPaused) {\n setShowControls(true);\n if (hideTimeout) {\n clearTimeout(hideTimeout);\n setHideTimeout(null);\n }\n } else {\n resetHideTimer();\n }\n }, [state.isPaused]);\n\n useEffect(() => {\n return () => {\n if (hideTimeout) {\n clearTimeout(hideTimeout);\n }\n };\n }, [hideTimeout]);\n\n const handleToggleControls = useCallback((e: React.MouseEvent | React.TouchEvent) => {\n const target = e.target as HTMLElement;\n if (target.closest('button, .controls-area')) {\n return;\n }\n e.preventDefault();\n\n if (showControls) {\n setShowControls(false);\n } else {\n resetHideTimer();\n }\n }, [showControls, resetHideTimer]);\n\n const handleMouseMove = useCallback(() => {\n if (!state.isPaused) {\n resetHideTimer();\n }\n }, [state.isPaused, resetHideTimer]);\n\n return (\n <div\n className=\"absolute inset-0 z-20 pointer-events-auto\"\n onClick={handleToggleControls}\n onTouchEnd={handleToggleControls}\n onMouseMove={handleMouseMove}\n >\n <div\n className={`controls-area transition-opacity duration-300 ${\n showControls ? 'opacity-100' : 'opacity-0 pointer-events-none'\n }`}\n >\n <div className=\"absolute top-0 left-0 right-0 h-20 bg-gradient-to-b from-black/60 to-transparent pointer-events-none\" />\n\n {state.totalSlides > 1 && (\n <div className=\"absolute top-4 right-4 z-10 pointer-events-auto\">\n <div className=\"bg-black/50 backdrop-blur-sm px-3 py-1.5 rounded text-sm text-white font-medium\">\n {state.currentIndex + 1} / {state.totalSlides}\n </div>\n </div>\n )}\n\n {state.totalSlides > 1 && (\n <div className=\"absolute top-4 left-4 z-20 pointer-events-auto\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n controls.toggle();\n }}\n className=\"bg-black/40 backdrop-blur-sm p-2.5 rounded-full text-white hover:bg-black/60 transition-colors\"\n aria-label={state.isPaused ? 'Resume slideshow' : 'Pause slideshow'}\n >\n {state.isPaused ? (\n <svg className=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\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 )}\n </button>\n </div>\n )}\n\n <div className=\"absolute bottom-0 left-0 right-0 h-32 bg-gradient-to-t from-black/60 to-transparent pointer-events-none\" />\n\n {state.images[state.currentIndex]?.caption && (\n <div className=\"absolute bottom-16 left-4 right-16 z-10 pointer-events-none\">\n <div className=\"text-white\">\n <p className=\"text-base drop-shadow-lg\">{state.images[state.currentIndex].caption}</p>\n {state.images[state.currentIndex]?.alt && (\n <p className=\"text-sm text-white/70 mt-1 drop-shadow-lg\">{state.images[state.currentIndex].alt}</p>\n )}\n </div>\n </div>\n )}\n\n <div className=\"absolute bottom-4 right-4 z-20 pointer-events-auto\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n tile.navigateToTile();\n }}\n className=\"bg-black/40 backdrop-blur-sm p-2.5 rounded-full text-white hover:bg-black/60 transition-colors\"\n aria-label=\"Minimize to tile\"\n >\n <svg className=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M20 12H4\" />\n </svg>\n </button>\n </div>\n </div>\n </div>\n );\n}\n\nexport default function PreviewPage() {\n return (\n <Slideshow\n
|
|
56
|
+
export declare const slideshowPreviewPageTemplate = "'use client';\n\nimport { Slideshow, TileProvider, useSlideshowState, useTile } from '@thewhateverapp/tile-sdk';\nimport { useState, useEffect, useCallback } from 'react';\n\n// Slideshow configuration injected at generation time\nconst SLIDESHOW_CONFIG = __SLIDESHOW_CONFIG__;\n\nfunction PageOverlay() {\n const tile = useTile();\n const { state, controls } = useSlideshowState();\n const [showControls, setShowControls] = useState(true);\n const [hideTimeout, setHideTimeout] = useState<NodeJS.Timeout | null>(null);\n\n const resetHideTimer = useCallback(() => {\n if (hideTimeout) {\n clearTimeout(hideTimeout);\n }\n setShowControls(true);\n\n if (!state.isPaused) {\n const timeout = setTimeout(() => {\n setShowControls(false);\n }, 3000);\n setHideTimeout(timeout);\n }\n }, [state.isPaused, hideTimeout]);\n\n useEffect(() => {\n if (state.isPaused) {\n setShowControls(true);\n if (hideTimeout) {\n clearTimeout(hideTimeout);\n setHideTimeout(null);\n }\n } else {\n resetHideTimer();\n }\n }, [state.isPaused]);\n\n useEffect(() => {\n return () => {\n if (hideTimeout) {\n clearTimeout(hideTimeout);\n }\n };\n }, [hideTimeout]);\n\n const handleToggleControls = useCallback((e: React.MouseEvent | React.TouchEvent) => {\n const target = e.target as HTMLElement;\n if (target.closest('button, .controls-area')) {\n return;\n }\n e.preventDefault();\n\n if (showControls) {\n setShowControls(false);\n } else {\n resetHideTimer();\n }\n }, [showControls, resetHideTimer]);\n\n const handleMouseMove = useCallback(() => {\n if (!state.isPaused) {\n resetHideTimer();\n }\n }, [state.isPaused, resetHideTimer]);\n\n return (\n <div\n className=\"absolute inset-0 z-20 pointer-events-auto\"\n onClick={handleToggleControls}\n onTouchEnd={handleToggleControls}\n onMouseMove={handleMouseMove}\n >\n <div\n className={`controls-area transition-opacity duration-300 ${\n showControls ? 'opacity-100' : 'opacity-0 pointer-events-none'\n }`}\n >\n <div className=\"absolute top-0 left-0 right-0 h-20 bg-gradient-to-b from-black/60 to-transparent pointer-events-none\" />\n\n {state.totalSlides > 1 && (\n <div className=\"absolute top-4 right-4 z-10 pointer-events-auto\">\n <div className=\"bg-black/50 backdrop-blur-sm px-3 py-1.5 rounded text-sm text-white font-medium\">\n {state.currentIndex + 1} / {state.totalSlides}\n </div>\n </div>\n )}\n\n {state.totalSlides > 1 && (\n <div className=\"absolute top-4 left-4 z-20 pointer-events-auto\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n controls.toggle();\n }}\n className=\"bg-black/40 backdrop-blur-sm p-2.5 rounded-full text-white hover:bg-black/60 transition-colors\"\n aria-label={state.isPaused ? 'Resume slideshow' : 'Pause slideshow'}\n >\n {state.isPaused ? (\n <svg className=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\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 )}\n </button>\n </div>\n )}\n\n <div className=\"absolute bottom-0 left-0 right-0 h-32 bg-gradient-to-t from-black/60 to-transparent pointer-events-none\" />\n\n {state.images[state.currentIndex]?.caption && (\n <div className=\"absolute bottom-16 left-4 right-16 z-10 pointer-events-none\">\n <div className=\"text-white\">\n <p className=\"text-base drop-shadow-lg\">{state.images[state.currentIndex].caption}</p>\n {state.images[state.currentIndex]?.alt && (\n <p className=\"text-sm text-white/70 mt-1 drop-shadow-lg\">{state.images[state.currentIndex].alt}</p>\n )}\n </div>\n </div>\n )}\n\n <div className=\"absolute bottom-4 right-4 z-20 pointer-events-auto\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n tile.navigateToTile();\n }}\n className=\"bg-black/40 backdrop-blur-sm p-2.5 rounded-full text-white hover:bg-black/60 transition-colors\"\n aria-label=\"Minimize to tile\"\n >\n <svg className=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M20 12H4\" />\n </svg>\n </button>\n </div>\n </div>\n </div>\n );\n}\n\nexport default function PreviewPage() {\n return (\n <TileProvider>\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 swipeable={true}\n className=\"w-full h-full object-cover\"\n >\n <PageOverlay />\n </Slideshow>\n </TileProvider>\n );\n}\n";
|
|
57
57
|
//# 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;;;;;;;;;;GAUG;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,
|
|
1
|
+
{"version":3,"file":"layout.tsx.template.d.ts","sourceRoot":"","sources":["../../../src/templates/slideshow/layout.tsx.template.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,uvBAyBnC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,0mGA0FxC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,m/LAmLxC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,k1FAiFxC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,82KAmKxC,CAAC"}
|
|
@@ -19,25 +19,27 @@
|
|
|
19
19
|
*/
|
|
20
20
|
export const slideshowLayoutTemplate = `'use client';
|
|
21
21
|
|
|
22
|
-
import { Slideshow } from '@thewhateverapp/tile-sdk';
|
|
22
|
+
import { Slideshow, TileProvider } from '@thewhateverapp/tile-sdk';
|
|
23
23
|
|
|
24
24
|
// Slideshow configuration injected at generation time
|
|
25
25
|
const SLIDESHOW_CONFIG = __SLIDESHOW_CONFIG__;
|
|
26
26
|
|
|
27
27
|
export default function SlideshowLayout({ children }: { children: React.ReactNode }) {
|
|
28
28
|
return (
|
|
29
|
-
<
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
29
|
+
<TileProvider>
|
|
30
|
+
<Slideshow
|
|
31
|
+
images={SLIDESHOW_CONFIG.images}
|
|
32
|
+
autoAdvance={SLIDESHOW_CONFIG.autoAdvance}
|
|
33
|
+
intervalMs={SLIDESHOW_CONFIG.intervalMs}
|
|
34
|
+
transition={SLIDESHOW_CONFIG.transition}
|
|
35
|
+
showDots={false}
|
|
36
|
+
showArrows={false}
|
|
37
|
+
className="w-full h-full"
|
|
38
|
+
>
|
|
39
|
+
{/* Children are the route-specific overlays */}
|
|
40
|
+
{children}
|
|
41
|
+
</Slideshow>
|
|
42
|
+
</TileProvider>
|
|
41
43
|
);
|
|
42
44
|
}
|
|
43
45
|
`;
|
|
@@ -338,7 +340,7 @@ function PageOverlay() {
|
|
|
338
340
|
*/
|
|
339
341
|
export const slideshowPreviewTileTemplate = `'use client';
|
|
340
342
|
|
|
341
|
-
import { Slideshow, useSlideshowState, useTile } from '@thewhateverapp/tile-sdk';
|
|
343
|
+
import { Slideshow, TileProvider, useSlideshowState, useTile } from '@thewhateverapp/tile-sdk';
|
|
342
344
|
|
|
343
345
|
// Slideshow configuration injected at generation time
|
|
344
346
|
const SLIDESHOW_CONFIG = __SLIDESHOW_CONFIG__;
|
|
@@ -402,17 +404,19 @@ function TileOverlay() {
|
|
|
402
404
|
|
|
403
405
|
export default function PreviewTile() {
|
|
404
406
|
return (
|
|
405
|
-
<
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
407
|
+
<TileProvider>
|
|
408
|
+
<Slideshow
|
|
409
|
+
images={SLIDESHOW_CONFIG.images}
|
|
410
|
+
autoAdvance={SLIDESHOW_CONFIG.autoAdvance}
|
|
411
|
+
intervalMs={SLIDESHOW_CONFIG.intervalMs}
|
|
412
|
+
transition={SLIDESHOW_CONFIG.transition}
|
|
413
|
+
showDots={false}
|
|
414
|
+
showArrows={false}
|
|
415
|
+
className="w-full h-full"
|
|
416
|
+
>
|
|
417
|
+
<TileOverlay />
|
|
418
|
+
</Slideshow>
|
|
419
|
+
</TileProvider>
|
|
416
420
|
);
|
|
417
421
|
}
|
|
418
422
|
`;
|
|
@@ -426,7 +430,7 @@ export default function PreviewTile() {
|
|
|
426
430
|
*/
|
|
427
431
|
export const slideshowPreviewPageTemplate = `'use client';
|
|
428
432
|
|
|
429
|
-
import { Slideshow, useSlideshowState, useTile } from '@thewhateverapp/tile-sdk';
|
|
433
|
+
import { Slideshow, TileProvider, useSlideshowState, useTile } from '@thewhateverapp/tile-sdk';
|
|
430
434
|
import { useState, useEffect, useCallback } from 'react';
|
|
431
435
|
|
|
432
436
|
// Slideshow configuration injected at generation time
|
|
@@ -571,18 +575,20 @@ function PageOverlay() {
|
|
|
571
575
|
|
|
572
576
|
export default function PreviewPage() {
|
|
573
577
|
return (
|
|
574
|
-
<
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
578
|
+
<TileProvider>
|
|
579
|
+
<Slideshow
|
|
580
|
+
images={SLIDESHOW_CONFIG.images}
|
|
581
|
+
autoAdvance={SLIDESHOW_CONFIG.autoAdvance}
|
|
582
|
+
intervalMs={SLIDESHOW_CONFIG.intervalMs}
|
|
583
|
+
transition={SLIDESHOW_CONFIG.transition}
|
|
584
|
+
showDots={true}
|
|
585
|
+
showArrows={true}
|
|
586
|
+
swipeable={true}
|
|
582
587
|
className="w-full h-full object-cover"
|
|
583
588
|
>
|
|
584
|
-
|
|
585
|
-
|
|
589
|
+
<PageOverlay />
|
|
590
|
+
</Slideshow>
|
|
591
|
+
</TileProvider>
|
|
586
592
|
);
|
|
587
593
|
}
|
|
588
594
|
`;
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*
|
|
18
18
|
* File path: src/app/(video)/layout.tsx
|
|
19
19
|
*/
|
|
20
|
-
export declare const videoLayoutTemplate = "'use client';\n\nimport { VideoPlayer } from '@thewhateverapp/tile-sdk';\n\nexport default function VideoLayout({ children }: { children: React.ReactNode }) {\n return (\n <VideoPlayer className=\"w-full h-full\">\n
|
|
20
|
+
export declare const videoLayoutTemplate = "'use client';\n\nimport { VideoPlayer, TileProvider } from '@thewhateverapp/tile-sdk';\n\nexport default function VideoLayout({ children }: { children: React.ReactNode }) {\n return (\n <TileProvider>\n <VideoPlayer className=\"w-full h-full\">\n {/* Children are the route-specific overlays */}\n {children}\n </VideoPlayer>\n </TileProvider>\n );\n}\n";
|
|
21
21
|
/**
|
|
22
22
|
* Video Tile Overlay Template
|
|
23
23
|
*
|
|
@@ -44,7 +44,7 @@ export declare const videoPageOverlayTemplate = "'use client';\n\nimport { useSt
|
|
|
44
44
|
*
|
|
45
45
|
* File path: src/app/_preview/tile.tsx
|
|
46
46
|
*/
|
|
47
|
-
export declare const videoPreviewTileTemplate = "'use client';\n\nimport { VideoPlayer, useVideoState, useTile } from '@thewhateverapp/tile-sdk';\nimport { useState, useEffect, useRef, useCallback } from 'react';\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\nconst CONTROLS_HIDE_DELAY = 3000;\n\nfunction TileOverlay() {\n const tile = useTile();\n const { state, controls } = useVideoState();\n\n const [hasInteracted, setHasInteracted] = useState(false);\n const [controlsVisible, setControlsVisible] = useState(false);\n const hideTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n\n const showControls = useCallback(() => {\n setHasInteracted(true);\n setControlsVisible(true);\n\n if (hideTimeoutRef.current) {\n clearTimeout(hideTimeoutRef.current);\n }\n\n if (state.isPlaying) {\n hideTimeoutRef.current = setTimeout(() => {\n setControlsVisible(false);\n }, CONTROLS_HIDE_DELAY);\n }\n }, [state.isPlaying]);\n\n useEffect(() => {\n if (!state.isPlaying && hasInteracted) {\n setControlsVisible(true);\n if (hideTimeoutRef.current) {\n clearTimeout(hideTimeoutRef.current);\n }\n }\n }, [state.isPlaying, hasInteracted]);\n\n useEffect(() => {\n return () => {\n if (hideTimeoutRef.current) {\n clearTimeout(hideTimeoutRef.current);\n }\n };\n }, []);\n\n const handleInteraction = useCallback(() => {\n if (!hasInteracted) {\n showControls();\n controls.toggle();\n } else if (controlsVisible) {\n controls.toggle();\n showControls();\n } else {\n showControls();\n }\n }, [hasInteracted, controlsVisible, showControls, controls]);\n\n const showCenterPlayButton = hasInteracted && !state.isPlaying && !state.isLoading && controlsVisible;\n const showBottomControls = hasInteracted && controlsVisible;\n\n return (\n <>\n <div\n className=\"absolute inset-0 z-5 pointer-events-auto cursor-pointer\"\n onClick={handleInteraction}\n onMouseMove={() => hasInteracted && showControls()}\n />\n\n <div className=\"absolute top-3 right-3 z-20 pointer-events-auto\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n tile.navigateToPage();\n }}\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-5 h-5\" 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 </div>\n\n <div\n className={`absolute inset-0 flex items-center justify-center z-10 pointer-events-none transition-opacity duration-300 ${\n showCenterPlayButton ? 'opacity-100' : 'opacity-0'\n }`}\n >\n <button\n onClick={(e) => {\n e.stopPropagation();\n controls.play();\n showControls();\n }}\n className=\"bg-black/50 backdrop-blur-sm p-4 rounded-full text-white hover:bg-black/70 transition-colors pointer-events-auto\"\n aria-label=\"Play video\"\n style={{ pointerEvents: showCenterPlayButton ? 'auto' : 'none' }}\n >\n <svg className=\"w-12 h-12\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n </button>\n </div>\n\n <div\n className={`absolute bottom-0 left-0 right-0 h-24 bg-gradient-to-t from-black/80 to-transparent pointer-events-none transition-opacity duration-300 ${\n showBottomControls ? 'opacity-100' : 'opacity-0'\n }`}\n />\n\n <div\n className={`absolute bottom-3 left-3 right-3 z-20 transition-opacity duration-300 ${\n showBottomControls ? 'opacity-100 pointer-events-auto' : 'opacity-0 pointer-events-none'\n }`}\n >\n <div\n className=\"h-1 bg-white/30 rounded-full overflow-hidden mb-2 cursor-pointer\"\n onClick={(e) => {\n e.stopPropagation();\n const rect = e.currentTarget.getBoundingClientRect();\n const percent = (e.clientX - rect.left) / rect.width;\n controls.seek(percent * state.duration);\n showControls();\n }}\n >\n <div\n className=\"h-full bg-white rounded-full transition-all duration-100\"\n style={{ width: `${(state.currentTime / state.duration) * 100 || 0}%` }}\n />\n </div>\n\n <div className=\"flex items-center justify-between text-white text-xs\">\n <div className=\"flex items-center gap-2\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n controls.toggle();\n showControls();\n }}\n className=\"p-1 hover:bg-white/20 rounded transition-colors\"\n aria-label={state.isPlaying ? 'Pause' : 'Play'}\n >\n {state.isPlaying ? (\n <svg className=\"w-4 h-4\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M6 4h4v16H6V4zm8 0h4v16h-4V4z\" />\n </svg>\n ) : (\n <svg className=\"w-4 h-4\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n )}\n </button>\n <span className=\"font-mono\">\n {formatTime(state.currentTime)} / {formatTime(state.duration)}\n </span>\n </div>\n\n <button\n onClick={(e) => {\n e.stopPropagation();\n controls.setMuted(!state.muted);\n showControls();\n }}\n className=\"p-1 hover:bg-white/20 rounded transition-colors\"\n aria-label={state.muted ? 'Unmute' : 'Mute'}\n >\n {state.muted ? (\n <svg className=\"w-4 h-4\" 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-4 h-4\" 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 </div>\n </div>\n </>\n );\n}\n\nexport default function PreviewTile() {\n return (\n <VideoPlayer className=\"w-full h-full\">\n
|
|
47
|
+
export declare const videoPreviewTileTemplate = "'use client';\n\nimport { VideoPlayer, TileProvider, useVideoState, useTile } from '@thewhateverapp/tile-sdk';\nimport { useState, useEffect, useRef, useCallback } from 'react';\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\nconst CONTROLS_HIDE_DELAY = 3000;\n\nfunction TileOverlay() {\n const tile = useTile();\n const { state, controls } = useVideoState();\n\n const [hasInteracted, setHasInteracted] = useState(false);\n const [controlsVisible, setControlsVisible] = useState(false);\n const hideTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n\n const showControls = useCallback(() => {\n setHasInteracted(true);\n setControlsVisible(true);\n\n if (hideTimeoutRef.current) {\n clearTimeout(hideTimeoutRef.current);\n }\n\n if (state.isPlaying) {\n hideTimeoutRef.current = setTimeout(() => {\n setControlsVisible(false);\n }, CONTROLS_HIDE_DELAY);\n }\n }, [state.isPlaying]);\n\n useEffect(() => {\n if (!state.isPlaying && hasInteracted) {\n setControlsVisible(true);\n if (hideTimeoutRef.current) {\n clearTimeout(hideTimeoutRef.current);\n }\n }\n }, [state.isPlaying, hasInteracted]);\n\n useEffect(() => {\n return () => {\n if (hideTimeoutRef.current) {\n clearTimeout(hideTimeoutRef.current);\n }\n };\n }, []);\n\n const handleInteraction = useCallback(() => {\n if (!hasInteracted) {\n showControls();\n controls.toggle();\n } else if (controlsVisible) {\n controls.toggle();\n showControls();\n } else {\n showControls();\n }\n }, [hasInteracted, controlsVisible, showControls, controls]);\n\n const showCenterPlayButton = hasInteracted && !state.isPlaying && !state.isLoading && controlsVisible;\n const showBottomControls = hasInteracted && controlsVisible;\n\n return (\n <>\n <div\n className=\"absolute inset-0 z-5 pointer-events-auto cursor-pointer\"\n onClick={handleInteraction}\n onMouseMove={() => hasInteracted && showControls()}\n />\n\n <div className=\"absolute top-3 right-3 z-20 pointer-events-auto\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n tile.navigateToPage();\n }}\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-5 h-5\" 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 </div>\n\n <div\n className={`absolute inset-0 flex items-center justify-center z-10 pointer-events-none transition-opacity duration-300 ${\n showCenterPlayButton ? 'opacity-100' : 'opacity-0'\n }`}\n >\n <button\n onClick={(e) => {\n e.stopPropagation();\n controls.play();\n showControls();\n }}\n className=\"bg-black/50 backdrop-blur-sm p-4 rounded-full text-white hover:bg-black/70 transition-colors pointer-events-auto\"\n aria-label=\"Play video\"\n style={{ pointerEvents: showCenterPlayButton ? 'auto' : 'none' }}\n >\n <svg className=\"w-12 h-12\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n </button>\n </div>\n\n <div\n className={`absolute bottom-0 left-0 right-0 h-24 bg-gradient-to-t from-black/80 to-transparent pointer-events-none transition-opacity duration-300 ${\n showBottomControls ? 'opacity-100' : 'opacity-0'\n }`}\n />\n\n <div\n className={`absolute bottom-3 left-3 right-3 z-20 transition-opacity duration-300 ${\n showBottomControls ? 'opacity-100 pointer-events-auto' : 'opacity-0 pointer-events-none'\n }`}\n >\n <div\n className=\"h-1 bg-white/30 rounded-full overflow-hidden mb-2 cursor-pointer\"\n onClick={(e) => {\n e.stopPropagation();\n const rect = e.currentTarget.getBoundingClientRect();\n const percent = (e.clientX - rect.left) / rect.width;\n controls.seek(percent * state.duration);\n showControls();\n }}\n >\n <div\n className=\"h-full bg-white rounded-full transition-all duration-100\"\n style={{ width: `${(state.currentTime / state.duration) * 100 || 0}%` }}\n />\n </div>\n\n <div className=\"flex items-center justify-between text-white text-xs\">\n <div className=\"flex items-center gap-2\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n controls.toggle();\n showControls();\n }}\n className=\"p-1 hover:bg-white/20 rounded transition-colors\"\n aria-label={state.isPlaying ? 'Pause' : 'Play'}\n >\n {state.isPlaying ? (\n <svg className=\"w-4 h-4\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M6 4h4v16H6V4zm8 0h4v16h-4V4z\" />\n </svg>\n ) : (\n <svg className=\"w-4 h-4\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n )}\n </button>\n <span className=\"font-mono\">\n {formatTime(state.currentTime)} / {formatTime(state.duration)}\n </span>\n </div>\n\n <button\n onClick={(e) => {\n e.stopPropagation();\n controls.setMuted(!state.muted);\n showControls();\n }}\n className=\"p-1 hover:bg-white/20 rounded transition-colors\"\n aria-label={state.muted ? 'Unmute' : 'Mute'}\n >\n {state.muted ? (\n <svg className=\"w-4 h-4\" 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-4 h-4\" 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 </div>\n </div>\n </>\n );\n}\n\nexport default function PreviewTile() {\n return (\n <TileProvider>\n <VideoPlayer className=\"w-full h-full\">\n <TileOverlay />\n </VideoPlayer>\n </TileProvider>\n );\n}\n";
|
|
48
48
|
/**
|
|
49
49
|
* Video Preview Entry - Page
|
|
50
50
|
*
|
|
@@ -53,5 +53,5 @@ export declare const videoPreviewTileTemplate = "'use client';\n\nimport { Video
|
|
|
53
53
|
*
|
|
54
54
|
* File path: src/app/_preview/page.tsx
|
|
55
55
|
*/
|
|
56
|
-
export declare const videoPreviewPageTemplate = "'use client';\n\nimport { VideoPlayer, useVideoState, useTile } from '@thewhateverapp/tile-sdk';\nimport { useState, useEffect, useCallback } from 'react';\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 tile = useTile();\n const { state, controls } = useVideoState();\n const [showControls, setShowControls] = useState(true);\n const [hideTimeout, setHideTimeout] = useState<NodeJS.Timeout | null>(null);\n\n const resetHideTimer = useCallback(() => {\n if (hideTimeout) {\n clearTimeout(hideTimeout);\n }\n setShowControls(true);\n\n if (state.isPlaying) {\n const timeout = setTimeout(() => {\n setShowControls(false);\n }, 3000);\n setHideTimeout(timeout);\n }\n }, [state.isPlaying, hideTimeout]);\n\n useEffect(() => {\n if (!state.isPlaying) {\n setShowControls(true);\n if (hideTimeout) {\n clearTimeout(hideTimeout);\n setHideTimeout(null);\n }\n } else {\n resetHideTimer();\n }\n }, [state.isPlaying]);\n\n useEffect(() => {\n return () => {\n if (hideTimeout) {\n clearTimeout(hideTimeout);\n }\n };\n }, [hideTimeout]);\n\n const handleToggleControls = useCallback((e: React.MouseEvent | React.TouchEvent) => {\n const target = e.target as HTMLElement;\n if (target.closest('button, .controls-area')) {\n return;\n }\n e.preventDefault();\n\n if (showControls) {\n setShowControls(false);\n } else {\n resetHideTimer();\n }\n }, [showControls, resetHideTimer]);\n\n const handleMouseMove = useCallback(() => {\n if (state.isPlaying) {\n resetHideTimer();\n }\n }, [state.isPlaying, resetHideTimer]);\n\n return (\n <div\n className=\"absolute inset-0 z-20 pointer-events-auto\"\n onClick={handleToggleControls}\n onTouchEnd={handleToggleControls}\n onMouseMove={handleMouseMove}\n >\n {!state.isPlaying && !state.isLoading && (\n <div className=\"absolute inset-0 flex items-center justify-center pointer-events-auto\">\n <button\n onClick={controls.play}\n className=\"bg-black/50 backdrop-blur-sm p-6 rounded-full text-white hover:bg-black/70 transition-colors\"\n aria-label=\"Play video\"\n >\n <svg className=\"w-16 h-16\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n </button>\n </div>\n )}\n\n <div\n className={`controls-area absolute bottom-0 left-0 right-0 transition-opacity duration-300 ${\n showControls ? 'opacity-100' : 'opacity-0 pointer-events-none'\n }`}\n >\n <div className=\"absolute bottom-0 left-0 right-0 h-32 bg-gradient-to-t from-black/80 to-transparent pointer-events-none\" />\n\n <div className=\"absolute bottom-4 left-4 right-4 z-20 pointer-events-auto\">\n <div\n className=\"h-1.5 bg-white/30 rounded-full overflow-hidden mb-3 cursor-pointer group hover:h-2 transition-all\"\n onClick={(e) => {\n e.stopPropagation();\n const rect = e.currentTarget.getBoundingClientRect();\n const percent = (e.clientX - rect.left) / rect.width;\n controls.seek(percent * state.duration);\n resetHideTimer();\n }}\n >\n <div\n className=\"h-full bg-white rounded-full transition-all duration-100 group-hover:bg-blue-400\"\n style={{ width: `${(state.currentTime / state.duration) * 100 || 0}%` }}\n />\n </div>\n\n <div className=\"flex items-center justify-between text-white\">\n <div className=\"flex items-center gap-3\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n controls.toggle();\n }}\n className=\"p-2 hover:bg-white/20 rounded-full transition-colors\"\n aria-label={state.isPlaying ? 'Pause' : 'Play'}\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 <button\n onClick={(e) => {\n e.stopPropagation();\n controls.setMuted(!state.muted);\n resetHideTimer();\n }}\n className=\"p-2 hover:bg-white/20 rounded-full transition-colors\"\n aria-label={state.muted ? 'Unmute' : 'Mute'}\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 <span className=\"text-sm font-mono\">\n {formatTime(state.currentTime)} / {formatTime(state.duration)}\n </span>\n </div>\n\n <button\n onClick={(e) => {\n e.stopPropagation();\n tile.navigateToTile();\n }}\n className=\"p-2 hover:bg-white/20 rounded-full transition-colors\"\n aria-label=\"Minimize to tile\"\n >\n <svg className=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M20 12H4\" />\n </svg>\n </button>\n </div>\n </div>\n </div>\n </div>\n );\n}\n\nexport default function PreviewPage() {\n return (\n <VideoPlayer className=\"w-full h-full\">\n
|
|
56
|
+
export declare const videoPreviewPageTemplate = "'use client';\n\nimport { VideoPlayer, TileProvider, useVideoState, useTile } from '@thewhateverapp/tile-sdk';\nimport { useState, useEffect, useCallback } from 'react';\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 tile = useTile();\n const { state, controls } = useVideoState();\n const [showControls, setShowControls] = useState(true);\n const [hideTimeout, setHideTimeout] = useState<NodeJS.Timeout | null>(null);\n\n const resetHideTimer = useCallback(() => {\n if (hideTimeout) {\n clearTimeout(hideTimeout);\n }\n setShowControls(true);\n\n if (state.isPlaying) {\n const timeout = setTimeout(() => {\n setShowControls(false);\n }, 3000);\n setHideTimeout(timeout);\n }\n }, [state.isPlaying, hideTimeout]);\n\n useEffect(() => {\n if (!state.isPlaying) {\n setShowControls(true);\n if (hideTimeout) {\n clearTimeout(hideTimeout);\n setHideTimeout(null);\n }\n } else {\n resetHideTimer();\n }\n }, [state.isPlaying]);\n\n useEffect(() => {\n return () => {\n if (hideTimeout) {\n clearTimeout(hideTimeout);\n }\n };\n }, [hideTimeout]);\n\n const handleToggleControls = useCallback((e: React.MouseEvent | React.TouchEvent) => {\n const target = e.target as HTMLElement;\n if (target.closest('button, .controls-area')) {\n return;\n }\n e.preventDefault();\n\n if (showControls) {\n setShowControls(false);\n } else {\n resetHideTimer();\n }\n }, [showControls, resetHideTimer]);\n\n const handleMouseMove = useCallback(() => {\n if (state.isPlaying) {\n resetHideTimer();\n }\n }, [state.isPlaying, resetHideTimer]);\n\n return (\n <div\n className=\"absolute inset-0 z-20 pointer-events-auto\"\n onClick={handleToggleControls}\n onTouchEnd={handleToggleControls}\n onMouseMove={handleMouseMove}\n >\n {!state.isPlaying && !state.isLoading && (\n <div className=\"absolute inset-0 flex items-center justify-center pointer-events-auto\">\n <button\n onClick={controls.play}\n className=\"bg-black/50 backdrop-blur-sm p-6 rounded-full text-white hover:bg-black/70 transition-colors\"\n aria-label=\"Play video\"\n >\n <svg className=\"w-16 h-16\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n </button>\n </div>\n )}\n\n <div\n className={`controls-area absolute bottom-0 left-0 right-0 transition-opacity duration-300 ${\n showControls ? 'opacity-100' : 'opacity-0 pointer-events-none'\n }`}\n >\n <div className=\"absolute bottom-0 left-0 right-0 h-32 bg-gradient-to-t from-black/80 to-transparent pointer-events-none\" />\n\n <div className=\"absolute bottom-4 left-4 right-4 z-20 pointer-events-auto\">\n <div\n className=\"h-1.5 bg-white/30 rounded-full overflow-hidden mb-3 cursor-pointer group hover:h-2 transition-all\"\n onClick={(e) => {\n e.stopPropagation();\n const rect = e.currentTarget.getBoundingClientRect();\n const percent = (e.clientX - rect.left) / rect.width;\n controls.seek(percent * state.duration);\n resetHideTimer();\n }}\n >\n <div\n className=\"h-full bg-white rounded-full transition-all duration-100 group-hover:bg-blue-400\"\n style={{ width: `${(state.currentTime / state.duration) * 100 || 0}%` }}\n />\n </div>\n\n <div className=\"flex items-center justify-between text-white\">\n <div className=\"flex items-center gap-3\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n controls.toggle();\n }}\n className=\"p-2 hover:bg-white/20 rounded-full transition-colors\"\n aria-label={state.isPlaying ? 'Pause' : 'Play'}\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 <button\n onClick={(e) => {\n e.stopPropagation();\n controls.setMuted(!state.muted);\n resetHideTimer();\n }}\n className=\"p-2 hover:bg-white/20 rounded-full transition-colors\"\n aria-label={state.muted ? 'Unmute' : 'Mute'}\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 <span className=\"text-sm font-mono\">\n {formatTime(state.currentTime)} / {formatTime(state.duration)}\n </span>\n </div>\n\n <button\n onClick={(e) => {\n e.stopPropagation();\n tile.navigateToTile();\n }}\n className=\"p-2 hover:bg-white/20 rounded-full transition-colors\"\n aria-label=\"Minimize to tile\"\n >\n <svg className=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M20 12H4\" />\n </svg>\n </button>\n </div>\n </div>\n </div>\n </div>\n );\n}\n\nexport default function PreviewPage() {\n return (\n <TileProvider>\n <VideoPlayer className=\"w-full h-full\">\n <PageOverlay />\n </VideoPlayer>\n </TileProvider>\n );\n}\n";
|
|
57
57
|
//# 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;;;;;;;;;;GAUG;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,
|
|
1
|
+
{"version":3,"file":"layout.tsx.template.d.ts","sourceRoot":"","sources":["../../../src/templates/video/layout.tsx.template.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,sYAc/B,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,2mOAkMpC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,+6OAyMpC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,myOAwMpC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,k8NA+LpC,CAAC"}
|
|
@@ -19,14 +19,16 @@
|
|
|
19
19
|
*/
|
|
20
20
|
export const videoLayoutTemplate = `'use client';
|
|
21
21
|
|
|
22
|
-
import { VideoPlayer } from '@thewhateverapp/tile-sdk';
|
|
22
|
+
import { VideoPlayer, TileProvider } from '@thewhateverapp/tile-sdk';
|
|
23
23
|
|
|
24
24
|
export default function VideoLayout({ children }: { children: React.ReactNode }) {
|
|
25
25
|
return (
|
|
26
|
-
<
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
<TileProvider>
|
|
27
|
+
<VideoPlayer className="w-full h-full">
|
|
28
|
+
{/* Children are the route-specific overlays */}
|
|
29
|
+
{children}
|
|
30
|
+
</VideoPlayer>
|
|
31
|
+
</TileProvider>
|
|
30
32
|
);
|
|
31
33
|
}
|
|
32
34
|
`;
|
|
@@ -453,7 +455,7 @@ export default PageOverlay;
|
|
|
453
455
|
*/
|
|
454
456
|
export const videoPreviewTileTemplate = `'use client';
|
|
455
457
|
|
|
456
|
-
import { VideoPlayer, useVideoState, useTile } from '@thewhateverapp/tile-sdk';
|
|
458
|
+
import { VideoPlayer, TileProvider, useVideoState, useTile } from '@thewhateverapp/tile-sdk';
|
|
457
459
|
import { useState, useEffect, useRef, useCallback } from 'react';
|
|
458
460
|
|
|
459
461
|
function formatTime(seconds: number): string {
|
|
@@ -644,9 +646,11 @@ function TileOverlay() {
|
|
|
644
646
|
|
|
645
647
|
export default function PreviewTile() {
|
|
646
648
|
return (
|
|
647
|
-
<
|
|
648
|
-
<
|
|
649
|
-
|
|
649
|
+
<TileProvider>
|
|
650
|
+
<VideoPlayer className="w-full h-full">
|
|
651
|
+
<TileOverlay />
|
|
652
|
+
</VideoPlayer>
|
|
653
|
+
</TileProvider>
|
|
650
654
|
);
|
|
651
655
|
}
|
|
652
656
|
`;
|
|
@@ -660,7 +664,7 @@ export default function PreviewTile() {
|
|
|
660
664
|
*/
|
|
661
665
|
export const videoPreviewPageTemplate = `'use client';
|
|
662
666
|
|
|
663
|
-
import { VideoPlayer, useVideoState, useTile } from '@thewhateverapp/tile-sdk';
|
|
667
|
+
import { VideoPlayer, TileProvider, useVideoState, useTile } from '@thewhateverapp/tile-sdk';
|
|
664
668
|
import { useState, useEffect, useCallback } from 'react';
|
|
665
669
|
|
|
666
670
|
function formatTime(seconds: number): string {
|
|
@@ -842,9 +846,11 @@ function PageOverlay() {
|
|
|
842
846
|
|
|
843
847
|
export default function PreviewPage() {
|
|
844
848
|
return (
|
|
845
|
-
<
|
|
846
|
-
<
|
|
847
|
-
|
|
849
|
+
<TileProvider>
|
|
850
|
+
<VideoPlayer className="w-full h-full">
|
|
851
|
+
<PageOverlay />
|
|
852
|
+
</VideoPlayer>
|
|
853
|
+
</TileProvider>
|
|
848
854
|
);
|
|
849
855
|
}
|
|
850
856
|
`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thewhateverapp/tile-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "SDK for building interactive tiles on The Whatever App platform",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -9,10 +9,6 @@
|
|
|
9
9
|
"types": "./dist/index.d.ts",
|
|
10
10
|
"import": "./dist/index.js"
|
|
11
11
|
},
|
|
12
|
-
"./react": {
|
|
13
|
-
"types": "./dist/react/index.d.ts",
|
|
14
|
-
"import": "./dist/react/index.js"
|
|
15
|
-
},
|
|
16
12
|
"./excalibur": {
|
|
17
13
|
"types": "./dist/excalibur/index.d.ts",
|
|
18
14
|
"import": "./dist/excalibur/index.js"
|
|
@@ -20,22 +16,6 @@
|
|
|
20
16
|
"./spec": {
|
|
21
17
|
"types": "./dist/spec/index.d.ts",
|
|
22
18
|
"import": "./dist/spec/index.js"
|
|
23
|
-
},
|
|
24
|
-
"./tools": {
|
|
25
|
-
"types": "./dist/tools/index.d.ts",
|
|
26
|
-
"import": "./dist/tools/index.js"
|
|
27
|
-
},
|
|
28
|
-
"./templates": {
|
|
29
|
-
"types": "./dist/templates/index.d.ts",
|
|
30
|
-
"import": "./dist/templates/index.js"
|
|
31
|
-
},
|
|
32
|
-
"./templates/video": {
|
|
33
|
-
"types": "./dist/templates/video/index.d.ts",
|
|
34
|
-
"import": "./dist/templates/video/index.js"
|
|
35
|
-
},
|
|
36
|
-
"./scene": {
|
|
37
|
-
"types": "./dist/scene/index.d.ts",
|
|
38
|
-
"import": "./dist/scene/index.js"
|
|
39
19
|
}
|
|
40
20
|
},
|
|
41
21
|
"files": [
|