@gallop.software/studio 0.1.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/README.md +158 -0
- package/dist/StudioUI-4ST2P6R7.mjs +991 -0
- package/dist/StudioUI-4ST2P6R7.mjs.map +1 -0
- package/dist/StudioUI-BH7PWCKH.js +991 -0
- package/dist/StudioUI-BH7PWCKH.js.map +1 -0
- package/dist/handlers.d.mts +50 -0
- package/dist/handlers.d.ts +50 -0
- package/dist/handlers.js +575 -0
- package/dist/handlers.js.map +1 -0
- package/dist/handlers.mjs +575 -0
- package/dist/handlers.mjs.map +1 -0
- package/dist/index.d.mts +42 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.js +103 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +103 -0
- package/dist/index.mjs.map +1 -0
- package/dist/types-BvdwylVD.d.mts +75 -0
- package/dist/types-BvdwylVD.d.ts +75 -0
- package/package.json +68 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { a as ImageSize, S as SizeEntry, I as ImageEntry, b as StudioMeta } from './types-BvdwylVD.mjs';
|
|
3
|
+
export { C as CdnStatus, F as FileItem, c as StudioConfig } from './types-BvdwylVD.mjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Floating button that opens the Studio modal.
|
|
7
|
+
* Fixed position in bottom-right corner.
|
|
8
|
+
* Only renders in development mode.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* ```tsx
|
|
12
|
+
* import { StudioButton } from '@gallop.software/studio'
|
|
13
|
+
*
|
|
14
|
+
* // In your layout
|
|
15
|
+
* <StudioButton />
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
declare function StudioButton(): react_jsx_runtime.JSX.Element | null;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The meta object containing all image metadata.
|
|
22
|
+
* This is read from _data/_meta.json in the consuming project.
|
|
23
|
+
*/
|
|
24
|
+
declare const meta: StudioMeta;
|
|
25
|
+
/**
|
|
26
|
+
* Initialize meta from a JSON object (called during build/runtime)
|
|
27
|
+
*/
|
|
28
|
+
declare function initializeMeta(data: StudioMeta): void;
|
|
29
|
+
/**
|
|
30
|
+
* Get the resolved URL for an image, handling CDN vs local paths
|
|
31
|
+
*/
|
|
32
|
+
declare function getImageUrl(imageKey: string, size?: ImageSize): string | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Get the full image entry for a key
|
|
35
|
+
*/
|
|
36
|
+
declare function getStudioMeta(imageKey: string): ImageEntry | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* Get size data for an image
|
|
39
|
+
*/
|
|
40
|
+
declare function getImageSize(imageKey: string, size?: ImageSize): SizeEntry | undefined;
|
|
41
|
+
|
|
42
|
+
export { ImageEntry, ImageSize, SizeEntry, StudioButton, StudioMeta, getImageSize, getImageUrl, getStudioMeta, initializeMeta, meta };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { a as ImageSize, S as SizeEntry, I as ImageEntry, b as StudioMeta } from './types-BvdwylVD.js';
|
|
3
|
+
export { C as CdnStatus, F as FileItem, c as StudioConfig } from './types-BvdwylVD.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Floating button that opens the Studio modal.
|
|
7
|
+
* Fixed position in bottom-right corner.
|
|
8
|
+
* Only renders in development mode.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* ```tsx
|
|
12
|
+
* import { StudioButton } from '@gallop.software/studio'
|
|
13
|
+
*
|
|
14
|
+
* // In your layout
|
|
15
|
+
* <StudioButton />
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
declare function StudioButton(): react_jsx_runtime.JSX.Element | null;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The meta object containing all image metadata.
|
|
22
|
+
* This is read from _data/_meta.json in the consuming project.
|
|
23
|
+
*/
|
|
24
|
+
declare const meta: StudioMeta;
|
|
25
|
+
/**
|
|
26
|
+
* Initialize meta from a JSON object (called during build/runtime)
|
|
27
|
+
*/
|
|
28
|
+
declare function initializeMeta(data: StudioMeta): void;
|
|
29
|
+
/**
|
|
30
|
+
* Get the resolved URL for an image, handling CDN vs local paths
|
|
31
|
+
*/
|
|
32
|
+
declare function getImageUrl(imageKey: string, size?: ImageSize): string | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Get the full image entry for a key
|
|
35
|
+
*/
|
|
36
|
+
declare function getStudioMeta(imageKey: string): ImageEntry | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* Get size data for an image
|
|
39
|
+
*/
|
|
40
|
+
declare function getImageSize(imageKey: string, size?: ImageSize): SizeEntry | undefined;
|
|
41
|
+
|
|
42
|
+
export { ImageEntry, ImageSize, SizeEntry, StudioButton, StudioMeta, getImageSize, getImageUrl, getStudioMeta, initializeMeta, meta };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }"use client";
|
|
2
|
+
|
|
3
|
+
// src/components/StudioButton.tsx
|
|
4
|
+
var _react = require('react');
|
|
5
|
+
var _jsxruntime = require('react/jsx-runtime');
|
|
6
|
+
var StudioUI = _react.lazy.call(void 0, () => Promise.resolve().then(() => _interopRequireWildcard(require("./StudioUI-BH7PWCKH.js"))));
|
|
7
|
+
function StudioButton() {
|
|
8
|
+
const [isOpen, setIsOpen] = _react.useState.call(void 0, false);
|
|
9
|
+
if (process.env.NODE_ENV !== "development") {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
13
|
+
!isOpen && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
14
|
+
"button",
|
|
15
|
+
{
|
|
16
|
+
onClick: () => setIsOpen(true),
|
|
17
|
+
className: "fixed bottom-6 right-6 z-[9998] w-12 h-12 rounded-full bg-gradient-to-br from-purple-500 to-pink-500 text-white shadow-lg hover:shadow-xl hover:scale-105 transition-all duration-200 flex items-center justify-center group",
|
|
18
|
+
title: "Open Studio",
|
|
19
|
+
"aria-label": "Open Studio media manager",
|
|
20
|
+
children: [
|
|
21
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, ImageIcon, {}),
|
|
22
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "absolute inset-0 rounded-full bg-purple-400 opacity-0 group-hover:opacity-0 animate-ping" })
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
),
|
|
26
|
+
isOpen && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fixed inset-0 z-[9999]", children: [
|
|
27
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
28
|
+
"div",
|
|
29
|
+
{
|
|
30
|
+
className: "absolute inset-0 bg-black/50 backdrop-blur-sm",
|
|
31
|
+
onClick: () => setIsOpen(false)
|
|
32
|
+
}
|
|
33
|
+
),
|
|
34
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "absolute inset-8 bg-white rounded-2xl shadow-2xl flex flex-col overflow-hidden", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _react.Suspense, { fallback: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, LoadingState, {}), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioUI, { onClose: () => setIsOpen(false) }) }) })
|
|
35
|
+
] })
|
|
36
|
+
] });
|
|
37
|
+
}
|
|
38
|
+
function ImageIcon() {
|
|
39
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
40
|
+
"svg",
|
|
41
|
+
{
|
|
42
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
43
|
+
viewBox: "0 0 24 24",
|
|
44
|
+
fill: "none",
|
|
45
|
+
stroke: "currentColor",
|
|
46
|
+
strokeWidth: 2,
|
|
47
|
+
strokeLinecap: "round",
|
|
48
|
+
strokeLinejoin: "round",
|
|
49
|
+
className: "w-6 h-6",
|
|
50
|
+
children: [
|
|
51
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
|
|
52
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
|
|
53
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "polyline", { points: "21 15 16 10 5 21" })
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
function LoadingState() {
|
|
59
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex items-center justify-center h-full", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col items-center gap-4", children: [
|
|
60
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "animate-spin rounded-full h-8 w-8 border-b-2 border-purple-600" }),
|
|
61
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-gray-500", children: "Loading Studio..." })
|
|
62
|
+
] }) });
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// src/lib/meta.ts
|
|
66
|
+
var _meta = {
|
|
67
|
+
$schema: "https://gallop.software/schemas/studio-meta.json",
|
|
68
|
+
version: 1,
|
|
69
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
70
|
+
images: {}
|
|
71
|
+
};
|
|
72
|
+
var meta = _meta;
|
|
73
|
+
function initializeMeta(data) {
|
|
74
|
+
_meta = data;
|
|
75
|
+
Object.assign(meta, data);
|
|
76
|
+
}
|
|
77
|
+
function getImageUrl(imageKey, size = "medium") {
|
|
78
|
+
const image = meta.images[imageKey];
|
|
79
|
+
if (!image) return void 0;
|
|
80
|
+
const sizeData = image.sizes[size] || image.sizes.full;
|
|
81
|
+
if (!sizeData) return void 0;
|
|
82
|
+
if (_optionalChain([image, 'access', _ => _.cdn, 'optionalAccess', _2 => _2.synced]) && image.cdn.baseUrl) {
|
|
83
|
+
return `${image.cdn.baseUrl}${sizeData.path}`;
|
|
84
|
+
}
|
|
85
|
+
return sizeData.path;
|
|
86
|
+
}
|
|
87
|
+
function getStudioMeta(imageKey) {
|
|
88
|
+
return meta.images[imageKey];
|
|
89
|
+
}
|
|
90
|
+
function getImageSize(imageKey, size = "medium") {
|
|
91
|
+
const image = meta.images[imageKey];
|
|
92
|
+
if (!image) return void 0;
|
|
93
|
+
return image.sizes[size] || image.sizes.full;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
exports.StudioButton = StudioButton; exports.getImageSize = getImageSize; exports.getImageUrl = getImageUrl; exports.getStudioMeta = getStudioMeta; exports.initializeMeta = initializeMeta; exports.meta = meta;
|
|
103
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/chrisb/Sites/studio/dist/index.js","../src/components/StudioButton.tsx","../src/lib/meta.ts"],"names":[],"mappings":"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","file":"/Users/chrisb/Sites/studio/dist/index.js","sourcesContent":[null,"'use client'\n\nimport { useState, lazy, Suspense } from 'react'\n\n// Lazy load the full Studio UI to avoid bundling in production\nconst StudioUI = lazy(() => import('./StudioUI'))\n\n/**\n * Floating button that opens the Studio modal.\n * Fixed position in bottom-right corner.\n * Only renders in development mode.\n * \n * Usage:\n * ```tsx\n * import { StudioButton } from '@gallop.software/studio'\n * \n * // In your layout\n * <StudioButton />\n * ```\n */\nexport function StudioButton() {\n const [isOpen, setIsOpen] = useState(false)\n\n // Only render in development\n if (process.env.NODE_ENV !== 'development') {\n return null\n }\n\n return (\n <>\n {/* Floating button - hidden when modal is open */}\n {!isOpen && (\n <button\n onClick={() => setIsOpen(true)}\n className=\"fixed bottom-6 right-6 z-[9998] w-12 h-12 rounded-full bg-gradient-to-br from-purple-500 to-pink-500 text-white shadow-lg hover:shadow-xl hover:scale-105 transition-all duration-200 flex items-center justify-center group\"\n title=\"Open Studio\"\n aria-label=\"Open Studio media manager\"\n >\n <ImageIcon />\n <span className=\"absolute inset-0 rounded-full bg-purple-400 opacity-0 group-hover:opacity-0 animate-ping\" />\n </button>\n )}\n\n {/* Modal overlay with lazy-loaded UI */}\n {isOpen && (\n <div className=\"fixed inset-0 z-[9999]\">\n {/* Backdrop */}\n <div\n className=\"absolute inset-0 bg-black/50 backdrop-blur-sm\"\n onClick={() => setIsOpen(false)}\n />\n\n {/* Modal */}\n <div className=\"absolute inset-8 bg-white rounded-2xl shadow-2xl flex flex-col overflow-hidden\">\n <Suspense fallback={<LoadingState />}>\n <StudioUI onClose={() => setIsOpen(false)} />\n </Suspense>\n </div>\n </div>\n )}\n </>\n )\n}\n\nfunction ImageIcon() {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"w-6 h-6\"\n >\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\" />\n <circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\" />\n <polyline points=\"21 15 16 10 5 21\" />\n </svg>\n )\n}\n\nfunction LoadingState() {\n return (\n <div className=\"flex items-center justify-center h-full\">\n <div className=\"flex flex-col items-center gap-4\">\n <div className=\"animate-spin rounded-full h-8 w-8 border-b-2 border-purple-600\" />\n <p className=\"text-gray-500\">Loading Studio...</p>\n </div>\n </div>\n )\n}\n","import type { StudioMeta, ImageEntry, ImageSize, SizeEntry } from '../types'\n\n// Default empty meta - will be populated when reading from project\nlet _meta: StudioMeta = {\n $schema: 'https://gallop.software/schemas/studio-meta.json',\n version: 1,\n generatedAt: new Date().toISOString(),\n images: {},\n}\n\n/**\n * The meta object containing all image metadata.\n * This is read from _data/_meta.json in the consuming project.\n */\nexport const meta: StudioMeta = _meta\n\n/**\n * Initialize meta from a JSON object (called during build/runtime)\n */\nexport function initializeMeta(data: StudioMeta): void {\n _meta = data\n Object.assign(meta, data)\n}\n\n/**\n * Get the resolved URL for an image, handling CDN vs local paths\n */\nexport function getImageUrl(\n imageKey: string,\n size: ImageSize = 'medium'\n): string | undefined {\n const image = meta.images[imageKey]\n if (!image) return undefined\n\n const sizeData = image.sizes[size] || image.sizes.full\n if (!sizeData) return undefined\n\n // If synced to CDN, use CDN URL\n if (image.cdn?.synced && image.cdn.baseUrl) {\n return `${image.cdn.baseUrl}${sizeData.path}`\n }\n\n // Otherwise use local path\n return sizeData.path\n}\n\n/**\n * Get the full image entry for a key\n */\nexport function getStudioMeta(imageKey: string): ImageEntry | undefined {\n return meta.images[imageKey]\n}\n\n/**\n * Get size data for an image\n */\nexport function getImageSize(\n imageKey: string,\n size: ImageSize = 'medium'\n): SizeEntry | undefined {\n const image = meta.images[imageKey]\n if (!image) return undefined\n return image.sizes[size] || image.sizes.full\n}\n"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/components/StudioButton.tsx
|
|
4
|
+
import { useState, lazy, Suspense } from "react";
|
|
5
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
var StudioUI = lazy(() => import("./StudioUI-4ST2P6R7.mjs"));
|
|
7
|
+
function StudioButton() {
|
|
8
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
9
|
+
if (process.env.NODE_ENV !== "development") {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
13
|
+
!isOpen && /* @__PURE__ */ jsxs(
|
|
14
|
+
"button",
|
|
15
|
+
{
|
|
16
|
+
onClick: () => setIsOpen(true),
|
|
17
|
+
className: "fixed bottom-6 right-6 z-[9998] w-12 h-12 rounded-full bg-gradient-to-br from-purple-500 to-pink-500 text-white shadow-lg hover:shadow-xl hover:scale-105 transition-all duration-200 flex items-center justify-center group",
|
|
18
|
+
title: "Open Studio",
|
|
19
|
+
"aria-label": "Open Studio media manager",
|
|
20
|
+
children: [
|
|
21
|
+
/* @__PURE__ */ jsx(ImageIcon, {}),
|
|
22
|
+
/* @__PURE__ */ jsx("span", { className: "absolute inset-0 rounded-full bg-purple-400 opacity-0 group-hover:opacity-0 animate-ping" })
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
),
|
|
26
|
+
isOpen && /* @__PURE__ */ jsxs("div", { className: "fixed inset-0 z-[9999]", children: [
|
|
27
|
+
/* @__PURE__ */ jsx(
|
|
28
|
+
"div",
|
|
29
|
+
{
|
|
30
|
+
className: "absolute inset-0 bg-black/50 backdrop-blur-sm",
|
|
31
|
+
onClick: () => setIsOpen(false)
|
|
32
|
+
}
|
|
33
|
+
),
|
|
34
|
+
/* @__PURE__ */ jsx("div", { className: "absolute inset-8 bg-white rounded-2xl shadow-2xl flex flex-col overflow-hidden", children: /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(LoadingState, {}), children: /* @__PURE__ */ jsx(StudioUI, { onClose: () => setIsOpen(false) }) }) })
|
|
35
|
+
] })
|
|
36
|
+
] });
|
|
37
|
+
}
|
|
38
|
+
function ImageIcon() {
|
|
39
|
+
return /* @__PURE__ */ jsxs(
|
|
40
|
+
"svg",
|
|
41
|
+
{
|
|
42
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
43
|
+
viewBox: "0 0 24 24",
|
|
44
|
+
fill: "none",
|
|
45
|
+
stroke: "currentColor",
|
|
46
|
+
strokeWidth: 2,
|
|
47
|
+
strokeLinecap: "round",
|
|
48
|
+
strokeLinejoin: "round",
|
|
49
|
+
className: "w-6 h-6",
|
|
50
|
+
children: [
|
|
51
|
+
/* @__PURE__ */ jsx("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
|
|
52
|
+
/* @__PURE__ */ jsx("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
|
|
53
|
+
/* @__PURE__ */ jsx("polyline", { points: "21 15 16 10 5 21" })
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
function LoadingState() {
|
|
59
|
+
return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-full", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-4", children: [
|
|
60
|
+
/* @__PURE__ */ jsx("div", { className: "animate-spin rounded-full h-8 w-8 border-b-2 border-purple-600" }),
|
|
61
|
+
/* @__PURE__ */ jsx("p", { className: "text-gray-500", children: "Loading Studio..." })
|
|
62
|
+
] }) });
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// src/lib/meta.ts
|
|
66
|
+
var _meta = {
|
|
67
|
+
$schema: "https://gallop.software/schemas/studio-meta.json",
|
|
68
|
+
version: 1,
|
|
69
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
70
|
+
images: {}
|
|
71
|
+
};
|
|
72
|
+
var meta = _meta;
|
|
73
|
+
function initializeMeta(data) {
|
|
74
|
+
_meta = data;
|
|
75
|
+
Object.assign(meta, data);
|
|
76
|
+
}
|
|
77
|
+
function getImageUrl(imageKey, size = "medium") {
|
|
78
|
+
const image = meta.images[imageKey];
|
|
79
|
+
if (!image) return void 0;
|
|
80
|
+
const sizeData = image.sizes[size] || image.sizes.full;
|
|
81
|
+
if (!sizeData) return void 0;
|
|
82
|
+
if (image.cdn?.synced && image.cdn.baseUrl) {
|
|
83
|
+
return `${image.cdn.baseUrl}${sizeData.path}`;
|
|
84
|
+
}
|
|
85
|
+
return sizeData.path;
|
|
86
|
+
}
|
|
87
|
+
function getStudioMeta(imageKey) {
|
|
88
|
+
return meta.images[imageKey];
|
|
89
|
+
}
|
|
90
|
+
function getImageSize(imageKey, size = "medium") {
|
|
91
|
+
const image = meta.images[imageKey];
|
|
92
|
+
if (!image) return void 0;
|
|
93
|
+
return image.sizes[size] || image.sizes.full;
|
|
94
|
+
}
|
|
95
|
+
export {
|
|
96
|
+
StudioButton,
|
|
97
|
+
getImageSize,
|
|
98
|
+
getImageUrl,
|
|
99
|
+
getStudioMeta,
|
|
100
|
+
initializeMeta,
|
|
101
|
+
meta
|
|
102
|
+
};
|
|
103
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/StudioButton.tsx","../src/lib/meta.ts"],"sourcesContent":["'use client'\n\nimport { useState, lazy, Suspense } from 'react'\n\n// Lazy load the full Studio UI to avoid bundling in production\nconst StudioUI = lazy(() => import('./StudioUI'))\n\n/**\n * Floating button that opens the Studio modal.\n * Fixed position in bottom-right corner.\n * Only renders in development mode.\n * \n * Usage:\n * ```tsx\n * import { StudioButton } from '@gallop.software/studio'\n * \n * // In your layout\n * <StudioButton />\n * ```\n */\nexport function StudioButton() {\n const [isOpen, setIsOpen] = useState(false)\n\n // Only render in development\n if (process.env.NODE_ENV !== 'development') {\n return null\n }\n\n return (\n <>\n {/* Floating button - hidden when modal is open */}\n {!isOpen && (\n <button\n onClick={() => setIsOpen(true)}\n className=\"fixed bottom-6 right-6 z-[9998] w-12 h-12 rounded-full bg-gradient-to-br from-purple-500 to-pink-500 text-white shadow-lg hover:shadow-xl hover:scale-105 transition-all duration-200 flex items-center justify-center group\"\n title=\"Open Studio\"\n aria-label=\"Open Studio media manager\"\n >\n <ImageIcon />\n <span className=\"absolute inset-0 rounded-full bg-purple-400 opacity-0 group-hover:opacity-0 animate-ping\" />\n </button>\n )}\n\n {/* Modal overlay with lazy-loaded UI */}\n {isOpen && (\n <div className=\"fixed inset-0 z-[9999]\">\n {/* Backdrop */}\n <div\n className=\"absolute inset-0 bg-black/50 backdrop-blur-sm\"\n onClick={() => setIsOpen(false)}\n />\n\n {/* Modal */}\n <div className=\"absolute inset-8 bg-white rounded-2xl shadow-2xl flex flex-col overflow-hidden\">\n <Suspense fallback={<LoadingState />}>\n <StudioUI onClose={() => setIsOpen(false)} />\n </Suspense>\n </div>\n </div>\n )}\n </>\n )\n}\n\nfunction ImageIcon() {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"w-6 h-6\"\n >\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\" />\n <circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\" />\n <polyline points=\"21 15 16 10 5 21\" />\n </svg>\n )\n}\n\nfunction LoadingState() {\n return (\n <div className=\"flex items-center justify-center h-full\">\n <div className=\"flex flex-col items-center gap-4\">\n <div className=\"animate-spin rounded-full h-8 w-8 border-b-2 border-purple-600\" />\n <p className=\"text-gray-500\">Loading Studio...</p>\n </div>\n </div>\n )\n}\n","import type { StudioMeta, ImageEntry, ImageSize, SizeEntry } from '../types'\n\n// Default empty meta - will be populated when reading from project\nlet _meta: StudioMeta = {\n $schema: 'https://gallop.software/schemas/studio-meta.json',\n version: 1,\n generatedAt: new Date().toISOString(),\n images: {},\n}\n\n/**\n * The meta object containing all image metadata.\n * This is read from _data/_meta.json in the consuming project.\n */\nexport const meta: StudioMeta = _meta\n\n/**\n * Initialize meta from a JSON object (called during build/runtime)\n */\nexport function initializeMeta(data: StudioMeta): void {\n _meta = data\n Object.assign(meta, data)\n}\n\n/**\n * Get the resolved URL for an image, handling CDN vs local paths\n */\nexport function getImageUrl(\n imageKey: string,\n size: ImageSize = 'medium'\n): string | undefined {\n const image = meta.images[imageKey]\n if (!image) return undefined\n\n const sizeData = image.sizes[size] || image.sizes.full\n if (!sizeData) return undefined\n\n // If synced to CDN, use CDN URL\n if (image.cdn?.synced && image.cdn.baseUrl) {\n return `${image.cdn.baseUrl}${sizeData.path}`\n }\n\n // Otherwise use local path\n return sizeData.path\n}\n\n/**\n * Get the full image entry for a key\n */\nexport function getStudioMeta(imageKey: string): ImageEntry | undefined {\n return meta.images[imageKey]\n}\n\n/**\n * Get size data for an image\n */\nexport function getImageSize(\n imageKey: string,\n size: ImageSize = 'medium'\n): SizeEntry | undefined {\n const image = meta.images[imageKey]\n if (!image) return undefined\n return image.sizes[size] || image.sizes.full\n}\n"],"mappings":";;;AAEA,SAAS,UAAU,MAAM,gBAAgB;AA2BrC,mBASM,KANF,YAHJ;AAxBJ,IAAM,WAAW,KAAK,MAAM,OAAO,yBAAY,CAAC;AAezC,SAAS,eAAe;AAC7B,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK;AAG1C,MAAI,QAAQ,IAAI,aAAa,eAAe;AAC1C,WAAO;AAAA,EACT;AAEA,SACE,iCAEG;AAAA,KAAC,UACA;AAAA,MAAC;AAAA;AAAA,QACC,SAAS,MAAM,UAAU,IAAI;AAAA,QAC7B,WAAU;AAAA,QACV,OAAM;AAAA,QACN,cAAW;AAAA,QAEX;AAAA,8BAAC,aAAU;AAAA,UACX,oBAAC,UAAK,WAAU,4FAA2F;AAAA;AAAA;AAAA,IAC7G;AAAA,IAID,UACC,qBAAC,SAAI,WAAU,0BAEb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,SAAS,MAAM,UAAU,KAAK;AAAA;AAAA,MAChC;AAAA,MAGA,oBAAC,SAAI,WAAU,kFACb,8BAAC,YAAS,UAAU,oBAAC,gBAAa,GAChC,8BAAC,YAAS,SAAS,MAAM,UAAU,KAAK,GAAG,GAC7C,GACF;AAAA,OACF;AAAA,KAEJ;AAEJ;AAEA,SAAS,YAAY;AACnB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAM;AAAA,MACN,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAa;AAAA,MACb,eAAc;AAAA,MACd,gBAAe;AAAA,MACf,WAAU;AAAA,MAEV;AAAA,4BAAC,UAAK,GAAE,KAAI,GAAE,KAAI,OAAM,MAAK,QAAO,MAAK,IAAG,KAAI,IAAG,KAAI;AAAA,QACvD,oBAAC,YAAO,IAAG,OAAM,IAAG,OAAM,GAAE,OAAM;AAAA,QAClC,oBAAC,cAAS,QAAO,oBAAmB;AAAA;AAAA;AAAA,EACtC;AAEJ;AAEA,SAAS,eAAe;AACtB,SACE,oBAAC,SAAI,WAAU,2CACb,+BAAC,SAAI,WAAU,oCACb;AAAA,wBAAC,SAAI,WAAU,kEAAiE;AAAA,IAChF,oBAAC,OAAE,WAAU,iBAAgB,+BAAiB;AAAA,KAChD,GACF;AAEJ;;;ACzFA,IAAI,QAAoB;AAAA,EACtB,SAAS;AAAA,EACT,SAAS;AAAA,EACT,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,EACpC,QAAQ,CAAC;AACX;AAMO,IAAM,OAAmB;AAKzB,SAAS,eAAe,MAAwB;AACrD,UAAQ;AACR,SAAO,OAAO,MAAM,IAAI;AAC1B;AAKO,SAAS,YACd,UACA,OAAkB,UACE;AACpB,QAAM,QAAQ,KAAK,OAAO,QAAQ;AAClC,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,WAAW,MAAM,MAAM,IAAI,KAAK,MAAM,MAAM;AAClD,MAAI,CAAC,SAAU,QAAO;AAGtB,MAAI,MAAM,KAAK,UAAU,MAAM,IAAI,SAAS;AAC1C,WAAO,GAAG,MAAM,IAAI,OAAO,GAAG,SAAS,IAAI;AAAA,EAC7C;AAGA,SAAO,SAAS;AAClB;AAKO,SAAS,cAAc,UAA0C;AACtE,SAAO,KAAK,OAAO,QAAQ;AAC7B;AAKO,SAAS,aACd,UACA,OAAkB,UACK;AACvB,QAAM,QAAQ,KAAK,OAAO,QAAQ;AAClC,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,MAAM,MAAM,IAAI,KAAK,MAAM,MAAM;AAC1C;","names":[]}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Image size variants
|
|
3
|
+
*/
|
|
4
|
+
type ImageSize = 'small' | 'medium' | 'large' | 'full';
|
|
5
|
+
/**
|
|
6
|
+
* Size entry with path and dimensions
|
|
7
|
+
*/
|
|
8
|
+
interface SizeEntry {
|
|
9
|
+
path: string;
|
|
10
|
+
width: number;
|
|
11
|
+
height: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* CDN sync status
|
|
15
|
+
*/
|
|
16
|
+
interface CdnStatus {
|
|
17
|
+
synced: boolean;
|
|
18
|
+
baseUrl: string;
|
|
19
|
+
syncedAt: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Image entry in meta
|
|
23
|
+
*/
|
|
24
|
+
interface ImageEntry {
|
|
25
|
+
original: {
|
|
26
|
+
path: string;
|
|
27
|
+
width: number;
|
|
28
|
+
height: number;
|
|
29
|
+
fileSize: number;
|
|
30
|
+
};
|
|
31
|
+
sizes: Record<ImageSize, SizeEntry>;
|
|
32
|
+
blurhash: string;
|
|
33
|
+
dominantColor: string;
|
|
34
|
+
cdn: CdnStatus | null;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Studio meta schema
|
|
38
|
+
*/
|
|
39
|
+
interface StudioMeta {
|
|
40
|
+
$schema: string;
|
|
41
|
+
version: number;
|
|
42
|
+
generatedAt: string;
|
|
43
|
+
images: Record<string, ImageEntry>;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* File/folder item for browser
|
|
47
|
+
*/
|
|
48
|
+
interface FileItem {
|
|
49
|
+
name: string;
|
|
50
|
+
path: string;
|
|
51
|
+
type: 'file' | 'folder';
|
|
52
|
+
size?: number;
|
|
53
|
+
dimensions?: {
|
|
54
|
+
width: number;
|
|
55
|
+
height: number;
|
|
56
|
+
};
|
|
57
|
+
cdnSynced?: boolean;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Studio configuration
|
|
61
|
+
*/
|
|
62
|
+
interface StudioConfig {
|
|
63
|
+
r2AccountId?: string;
|
|
64
|
+
r2AccessKeyId?: string;
|
|
65
|
+
r2SecretAccessKey?: string;
|
|
66
|
+
r2BucketName?: string;
|
|
67
|
+
r2PublicUrl?: string;
|
|
68
|
+
thumbnailSizes?: {
|
|
69
|
+
small: number;
|
|
70
|
+
medium: number;
|
|
71
|
+
large: number;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export type { CdnStatus as C, FileItem as F, ImageEntry as I, SizeEntry as S, ImageSize as a, StudioMeta as b, StudioConfig as c };
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Image size variants
|
|
3
|
+
*/
|
|
4
|
+
type ImageSize = 'small' | 'medium' | 'large' | 'full';
|
|
5
|
+
/**
|
|
6
|
+
* Size entry with path and dimensions
|
|
7
|
+
*/
|
|
8
|
+
interface SizeEntry {
|
|
9
|
+
path: string;
|
|
10
|
+
width: number;
|
|
11
|
+
height: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* CDN sync status
|
|
15
|
+
*/
|
|
16
|
+
interface CdnStatus {
|
|
17
|
+
synced: boolean;
|
|
18
|
+
baseUrl: string;
|
|
19
|
+
syncedAt: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Image entry in meta
|
|
23
|
+
*/
|
|
24
|
+
interface ImageEntry {
|
|
25
|
+
original: {
|
|
26
|
+
path: string;
|
|
27
|
+
width: number;
|
|
28
|
+
height: number;
|
|
29
|
+
fileSize: number;
|
|
30
|
+
};
|
|
31
|
+
sizes: Record<ImageSize, SizeEntry>;
|
|
32
|
+
blurhash: string;
|
|
33
|
+
dominantColor: string;
|
|
34
|
+
cdn: CdnStatus | null;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Studio meta schema
|
|
38
|
+
*/
|
|
39
|
+
interface StudioMeta {
|
|
40
|
+
$schema: string;
|
|
41
|
+
version: number;
|
|
42
|
+
generatedAt: string;
|
|
43
|
+
images: Record<string, ImageEntry>;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* File/folder item for browser
|
|
47
|
+
*/
|
|
48
|
+
interface FileItem {
|
|
49
|
+
name: string;
|
|
50
|
+
path: string;
|
|
51
|
+
type: 'file' | 'folder';
|
|
52
|
+
size?: number;
|
|
53
|
+
dimensions?: {
|
|
54
|
+
width: number;
|
|
55
|
+
height: number;
|
|
56
|
+
};
|
|
57
|
+
cdnSynced?: boolean;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Studio configuration
|
|
61
|
+
*/
|
|
62
|
+
interface StudioConfig {
|
|
63
|
+
r2AccountId?: string;
|
|
64
|
+
r2AccessKeyId?: string;
|
|
65
|
+
r2SecretAccessKey?: string;
|
|
66
|
+
r2BucketName?: string;
|
|
67
|
+
r2PublicUrl?: string;
|
|
68
|
+
thumbnailSizes?: {
|
|
69
|
+
small: number;
|
|
70
|
+
medium: number;
|
|
71
|
+
large: number;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export type { CdnStatus as C, FileItem as F, ImageEntry as I, SizeEntry as S, ImageSize as a, StudioMeta as b, StudioConfig as c };
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gallop.software/studio",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Media manager for Gallop templates - upload, process, and sync images to CDN",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./handlers": {
|
|
15
|
+
"types": "./dist/handlers.d.ts",
|
|
16
|
+
"import": "./dist/handlers.mjs",
|
|
17
|
+
"require": "./dist/handlers.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsup",
|
|
25
|
+
"dev": "tsup --watch",
|
|
26
|
+
"lint": "eslint src",
|
|
27
|
+
"typecheck": "tsc --noEmit",
|
|
28
|
+
"prepublishOnly": "npm run build"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"media-manager",
|
|
32
|
+
"image-processing",
|
|
33
|
+
"cloudflare-r2",
|
|
34
|
+
"nextjs",
|
|
35
|
+
"gallop",
|
|
36
|
+
"cdn"
|
|
37
|
+
],
|
|
38
|
+
"author": "Gallop Software",
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "https://github.com/gallop-software/studio.git"
|
|
43
|
+
},
|
|
44
|
+
"homepage": "https://github.com/gallop-software/studio#readme",
|
|
45
|
+
"bugs": {
|
|
46
|
+
"url": "https://github.com/gallop-software/studio/issues"
|
|
47
|
+
},
|
|
48
|
+
"peerDependencies": {
|
|
49
|
+
"next": ">=14.0.0",
|
|
50
|
+
"react": ">=18.0.0",
|
|
51
|
+
"react-dom": ">=18.0.0"
|
|
52
|
+
},
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"@aws-sdk/client-s3": "^3.705.0",
|
|
55
|
+
"blurhash": "^2.0.5",
|
|
56
|
+
"clsx": "^2.1.1",
|
|
57
|
+
"react-dropzone": "^14.3.5",
|
|
58
|
+
"sharp": "^0.33.5"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@types/node": "^22.10.5",
|
|
62
|
+
"@types/react": "^19.0.2",
|
|
63
|
+
"@types/react-dom": "^19.0.2",
|
|
64
|
+
"eslint": "^9.17.0",
|
|
65
|
+
"tsup": "^8.3.5",
|
|
66
|
+
"typescript": "^5.7.2"
|
|
67
|
+
}
|
|
68
|
+
}
|