@codellyson/framely-cli 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/commands/compositions.js +135 -0
- package/commands/preview.js +889 -0
- package/commands/render.js +295 -0
- package/commands/still.js +165 -0
- package/index.js +93 -0
- package/package.json +60 -0
- package/studio/App.css +605 -0
- package/studio/App.jsx +185 -0
- package/studio/CompositionsView.css +399 -0
- package/studio/CompositionsView.jsx +327 -0
- package/studio/PropsEditor.css +195 -0
- package/studio/PropsEditor.tsx +176 -0
- package/studio/RenderDialog.tsx +476 -0
- package/studio/ShareDialog.tsx +200 -0
- package/studio/index.ts +19 -0
- package/studio/player/Player.css +199 -0
- package/studio/player/Player.jsx +355 -0
- package/studio/styles/design-system.css +592 -0
- package/studio/styles/dialogs.css +420 -0
- package/studio/templates/AnimatedGradient.jsx +99 -0
- package/studio/templates/InstagramStory.jsx +172 -0
- package/studio/templates/LowerThird.jsx +139 -0
- package/studio/templates/ProductShowcase.jsx +162 -0
- package/studio/templates/SlideTransition.jsx +211 -0
- package/studio/templates/SocialIntro.jsx +122 -0
- package/studio/templates/SubscribeAnimation.jsx +186 -0
- package/studio/templates/TemplateCard.tsx +58 -0
- package/studio/templates/TemplateFilters.tsx +97 -0
- package/studio/templates/TemplatePreviewDialog.tsx +196 -0
- package/studio/templates/TemplatesMarketplace.css +686 -0
- package/studio/templates/TemplatesMarketplace.tsx +172 -0
- package/studio/templates/TextReveal.jsx +134 -0
- package/studio/templates/UseTemplateDialog.tsx +154 -0
- package/studio/templates/index.ts +45 -0
- package/utils/browser.js +188 -0
- package/utils/codecs.js +200 -0
- package/utils/logger.js +35 -0
- package/utils/props.js +42 -0
- package/utils/render.js +447 -0
- package/utils/validate.js +148 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compositions Command
|
|
3
|
+
*
|
|
4
|
+
* Lists all available compositions from the Framely project.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* framely compositions
|
|
8
|
+
* framely compositions --json
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import chalk from 'chalk';
|
|
12
|
+
import ora from 'ora';
|
|
13
|
+
import { createBrowser, closeBrowser } from '../utils/browser.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Main compositions command handler.
|
|
17
|
+
*/
|
|
18
|
+
export async function compositionsCommand(options) {
|
|
19
|
+
const spinner = ora();
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
if (!options.json) {
|
|
23
|
+
console.log(chalk.cyan('\nš Framely Compositions\n'));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// āāā Launch Browser to Fetch Compositions āāā
|
|
27
|
+
spinner.start('Fetching compositions...');
|
|
28
|
+
|
|
29
|
+
const { browser, page } = await createBrowser({
|
|
30
|
+
width: 100,
|
|
31
|
+
height: 100,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Navigate to frontend
|
|
35
|
+
await page.goto(options.frontendUrl, { waitUntil: 'networkidle', timeout: 30000 });
|
|
36
|
+
|
|
37
|
+
// Wait for app to be ready
|
|
38
|
+
try {
|
|
39
|
+
await page.waitForFunction('window.__ready === true || window.__FRAMELY_COMPOSITIONS', {
|
|
40
|
+
timeout: 10000,
|
|
41
|
+
});
|
|
42
|
+
} catch {
|
|
43
|
+
// May not have ready flag in some setups
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Get compositions from global
|
|
47
|
+
const compositions = await page.evaluate(() => {
|
|
48
|
+
// Try different possible locations
|
|
49
|
+
if (window.__FRAMELY_COMPOSITIONS) {
|
|
50
|
+
return Object.values(window.__FRAMELY_COMPOSITIONS);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Try to extract from registry
|
|
54
|
+
if (window.__FRAMELY_ROOT) {
|
|
55
|
+
// This would require traversing the component tree
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return [];
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
spinner.stop();
|
|
63
|
+
|
|
64
|
+
// If no compositions found, try the API endpoint
|
|
65
|
+
if (compositions.length === 0) {
|
|
66
|
+
try {
|
|
67
|
+
const parsed = new URL(options.frontendUrl);
|
|
68
|
+
parsed.port = String(parseInt(parsed.port || '3000', 10) + 1);
|
|
69
|
+
const response = await fetch(`${parsed.origin}/api/compositions`);
|
|
70
|
+
if (response.ok) {
|
|
71
|
+
const data = await response.json();
|
|
72
|
+
compositions.push(...(data.compositions || []));
|
|
73
|
+
}
|
|
74
|
+
} catch {
|
|
75
|
+
// API might not be running
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// āāā Output Results āāā
|
|
80
|
+
if (options.json) {
|
|
81
|
+
console.log(JSON.stringify(compositions, null, 2));
|
|
82
|
+
} else if (compositions.length === 0) {
|
|
83
|
+
console.log(chalk.yellow(' No compositions found.\n'));
|
|
84
|
+
console.log(chalk.gray(' Make sure the frontend is running and has registered compositions.'));
|
|
85
|
+
console.log(chalk.gray(' Use registerRoot() in your entry file to register compositions.\n'));
|
|
86
|
+
} else {
|
|
87
|
+
// Calculate column widths
|
|
88
|
+
const maxIdLength = Math.max(...compositions.map((c) => (c.id && c.id.length) || 0), 2);
|
|
89
|
+
|
|
90
|
+
// Header
|
|
91
|
+
console.log(
|
|
92
|
+
chalk.gray(' ') +
|
|
93
|
+
chalk.white('ID'.padEnd(maxIdLength + 2)) +
|
|
94
|
+
chalk.white('Resolution'.padEnd(14)) +
|
|
95
|
+
chalk.white('FPS'.padEnd(6)) +
|
|
96
|
+
chalk.white('Duration')
|
|
97
|
+
);
|
|
98
|
+
console.log(chalk.gray(' ' + 'ā'.repeat(maxIdLength + 40)));
|
|
99
|
+
|
|
100
|
+
// Rows
|
|
101
|
+
for (const comp of compositions) {
|
|
102
|
+
const id = (comp.id || 'unknown').padEnd(maxIdLength + 2);
|
|
103
|
+
const resolution = `${comp.width || '?'}x${comp.height || '?'}`.padEnd(14);
|
|
104
|
+
const fps = String(comp.fps || '?').padEnd(6);
|
|
105
|
+
const frames = comp.durationInFrames || '?';
|
|
106
|
+
const seconds = comp.fps ? (frames / comp.fps).toFixed(1) + 's' : '?';
|
|
107
|
+
const duration = `${frames} frames (${seconds})`;
|
|
108
|
+
|
|
109
|
+
console.log(
|
|
110
|
+
chalk.gray(' ') +
|
|
111
|
+
chalk.yellow(id) +
|
|
112
|
+
chalk.white(resolution) +
|
|
113
|
+
chalk.white(fps) +
|
|
114
|
+
chalk.gray(duration)
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
console.log(chalk.gray('\n ' + 'ā'.repeat(maxIdLength + 40)));
|
|
119
|
+
console.log(chalk.gray(` ${compositions.length} composition(s) found\n`));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
await closeBrowser(browser);
|
|
123
|
+
process.exit(0);
|
|
124
|
+
} catch (error) {
|
|
125
|
+
spinner.fail('Failed to fetch compositions');
|
|
126
|
+
console.error(chalk.red(`\nError: ${error.message}\n`));
|
|
127
|
+
|
|
128
|
+
if (!options.json) {
|
|
129
|
+
console.log(chalk.gray(' Make sure the frontend dev server is running:'));
|
|
130
|
+
console.log(chalk.cyan(' framely preview\n'));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
}
|