@minnai/create-aura-app 0.0.12 → 0.0.14

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.
Files changed (31) hide show
  1. package/package.json +1 -1
  2. package/templates/starter/package.json +2 -2
  3. package/templates/starter/src/src/App.css +0 -32
  4. package/templates/starter/src/src/App.tsx +0 -82
  5. package/templates/starter/src/src/ambiance/currency-air/index.tsx +0 -25
  6. package/templates/starter/src/src/ambiance/currency-air/logic.ts +0 -49
  7. package/templates/starter/src/src/ambiance/currency-air/manifest.ts +0 -15
  8. package/templates/starter/src/src/ambiance/currency-air/resources.ts +0 -16
  9. package/templates/starter/src/src/ambiance/currency-air/ui/index.tsx +0 -42
  10. package/templates/starter/src/src/ambiance/index.ts +0 -48
  11. package/templates/starter/src/src/ambiance/stocks-air/index.ts +0 -3
  12. package/templates/starter/src/src/ambiance/stocks-air/index.tsx +0 -28
  13. package/templates/starter/src/src/ambiance/stocks-air/logic.ts +0 -87
  14. package/templates/starter/src/src/ambiance/stocks-air/manifest.ts +0 -15
  15. package/templates/starter/src/src/ambiance/stocks-air/resources.ts +0 -23
  16. package/templates/starter/src/src/ambiance/stocks-air/ui/index.tsx +0 -67
  17. package/templates/starter/src/src/assets/react.svg +0 -1
  18. package/templates/starter/src/src/components/AnalyticsTracker.tsx +0 -13
  19. package/templates/starter/src/src/components/Playground/CodeEditor.tsx +0 -121
  20. package/templates/starter/src/src/components/Playground/Debugger.tsx +0 -71
  21. package/templates/starter/src/src/components/Playground/Playground.tsx +0 -221
  22. package/templates/starter/src/src/components/Playground/Sidebar.tsx +0 -68
  23. package/templates/starter/src/src/components/ProjectSidebar/ProjectSidebar.tsx +0 -219
  24. package/templates/starter/src/src/components/TourGuide/TourGuide.tsx +0 -16
  25. package/templates/starter/src/src/components/TourGuide/index.ts +0 -1
  26. package/templates/starter/src/src/components/TourGuide/tour-flow.yaml +0 -137
  27. package/templates/starter/src/src/components/TourGuide/useTourEngine.ts +0 -376
  28. package/templates/starter/src/src/index.css +0 -68
  29. package/templates/starter/src/src/main.tsx +0 -10
  30. package/templates/starter/src/src/services/AnalyticsService.ts +0 -181
  31. package/templates/starter/src/src/types/ContextHandler.ts +0 -13
@@ -1,121 +0,0 @@
1
- import { useState, useRef, useEffect } from 'react';
2
- import Editor from '@monaco-editor/react';
3
- import { atmosphere } from '@minnai/aura/atmosphere';
4
-
5
- interface CodeEditorProps {
6
- airId: string;
7
- filePath: string;
8
- initialCode: string;
9
- }
10
-
11
- export function CodeEditor({ airId, filePath, initialCode }: CodeEditorProps) {
12
- const [isDirty, setIsDirty] = useState(false);
13
- const [status, setStatus] = useState<'idle' | 'saving' | 'saved'>('idle');
14
- const editorRef = useRef<any>(null);
15
-
16
- function handleEditorDidMount(editor: any, monaco: any) {
17
- editorRef.current = editor;
18
-
19
- // Disable internal linting/errors
20
- monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({
21
- noSemanticValidation: true,
22
- noSyntaxValidation: true,
23
- });
24
- }
25
-
26
- const handleSave = async () => {
27
- const content = editorRef.current?.getValue() || '';
28
- setStatus('saving');
29
-
30
- try {
31
- // 1. Persist to Filesystem
32
- const response = await fetch('/api/save-code', {
33
- method: 'POST',
34
- headers: { 'Content-Type': 'application/json' },
35
- body: JSON.stringify({ filePath, content })
36
- });
37
-
38
- if (!response.ok) throw new Error("Failed to save to disk");
39
-
40
- setStatus('saved');
41
- setIsDirty(false);
42
- setTimeout(() => setStatus('idle'), 3000);
43
-
44
- // Note: Since we saved to the filesystem, Vite should ideally hot-reload.
45
- // But if user wants a manual reload of the AIR, we could trigger flux dispatch.
46
- // For now, persistence is verified.
47
- } catch (err: any) {
48
- console.error(err);
49
- alert("Save failed: " + err.message);
50
- setStatus('idle');
51
- }
52
- };
53
-
54
- return (
55
- <div style={{ display: 'flex', flexDirection: 'column', height: '100%', background: '#1e1e1e' }}>
56
- <div style={{
57
- padding: '10px 20px',
58
- background: '#2d2d2d',
59
- color: '#ddd',
60
- display: 'flex',
61
- justifyContent: 'space-between',
62
- alignItems: 'center',
63
- borderBottom: '1px solid #333',
64
- height: '40px',
65
- userSelect: 'none'
66
- }}>
67
- <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
68
- <span style={{ fontSize: '0.75rem', opacity: 0.7, fontFamily: 'monospace' }}>{filePath}</span>
69
- {isDirty && <span style={{ width: 8, height: 8, borderRadius: '50%', background: '#ff9500' }} title="Unsaved changes" />}
70
- </div>
71
-
72
- <div style={{ display: 'flex', alignItems: 'center', gap: 15 }}>
73
- {status === 'saved' && (
74
- <span style={{ fontSize: '0.75rem', color: '#4cd964', fontWeight: 600 }}>Saved ✔</span>
75
- )}
76
- {status === 'saving' && (
77
- <span style={{ fontSize: '0.75rem', color: '#888' }}>Saving...</span>
78
- )}
79
- <button
80
- onClick={handleSave}
81
- style={{
82
- padding: '4px 12px',
83
- background: isDirty ? '#007aff' : '#444',
84
- color: 'white',
85
- border: 'none',
86
- borderRadius: 4,
87
- cursor: isDirty ? 'pointer' : 'default',
88
- fontSize: '0.75rem',
89
- fontWeight: 600,
90
- transition: 'all 0.2s',
91
- opacity: isDirty ? 1 : 0.6
92
- }}
93
- >
94
- Save & Reload
95
- </button>
96
- </div>
97
- </div>
98
- <div style={{ flex: 1 }}>
99
- <Editor
100
- key={filePath} // Force re-mount when file changes
101
- height="100%"
102
- defaultLanguage="typescript"
103
- theme="vs-dark"
104
- value={initialCode}
105
- onChange={() => setIsDirty(true)}
106
- onMount={handleEditorDidMount}
107
- options={{
108
- minimap: { enabled: false },
109
- fontSize: 13,
110
- scrollBeyondLastLine: false,
111
- automaticLayout: true,
112
- tabSize: 4,
113
- padding: { top: 10 },
114
- wordWrap: 'on'
115
- }}
116
- />
117
- </div>
118
- </div>
119
- );
120
- }
121
-
@@ -1,71 +0,0 @@
1
- import { useEffect, useState } from 'react';
2
- import { flux } from '@minnai/aura/flux/index';
3
-
4
- interface DebuggerProps {
5
- airId: string;
6
- }
7
-
8
- export function Debugger({ airId }: DebuggerProps) {
9
- const [state] = useState<any>(null);
10
- const [history, setHistory] = useState<any[]>([]);
11
-
12
- useEffect(() => {
13
- // Listen to all flux actions (simplified for playground)
14
- const unsubscribe = flux.subscribe((action) => {
15
- if (action.to === airId || action.type.includes(airId.toUpperCase())) {
16
- setHistory(prev => [action, ...prev].slice(0, 20));
17
- }
18
-
19
- // Attempt to get current state (this requires a specific flux pattern or selector)
20
- // For now, we assume the state is exposed or we track updates
21
- });
22
-
23
- return () => unsubscribe();
24
- }, [airId]);
25
-
26
- return (
27
- <div style={{
28
- width: '350px',
29
- borderLeft: '1px solid #ddd',
30
- background: 'white',
31
- padding: '20px',
32
- display: 'flex',
33
- flexDirection: 'column',
34
- gap: '20px',
35
- overflowY: 'auto'
36
- }}>
37
- <section>
38
- <h3 style={{ margin: '0 0 10px 0', fontSize: '0.9rem', color: '#666', textTransform: 'uppercase' }}>State (Live)</h3>
39
- <pre style={{
40
- background: '#f8f8f8',
41
- padding: '10px',
42
- borderRadius: '6px',
43
- fontSize: '0.8rem',
44
- overflowX: 'auto',
45
- border: '1px solid #eee'
46
- }}>
47
- {JSON.stringify(state || { message: 'State tracking pending flux integration' }, null, 2)}
48
- </pre>
49
- </section>
50
-
51
- <section>
52
- <h3 style={{ margin: '0 0 10px 0', fontSize: '0.9rem', color: '#666', textTransform: 'uppercase' }}>Action History</h3>
53
- <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
54
- {history.length === 0 && <div style={{ fontSize: '0.8rem', color: '#999' }}>No recent actions</div>}
55
- {history.map((action, i) => (
56
- <div key={i} style={{
57
- fontSize: '0.75rem',
58
- padding: '8px',
59
- background: '#f0f0f0',
60
- borderRadius: '4px',
61
- borderLeft: '3px solid #007aff'
62
- }}>
63
- <div style={{ fontWeight: 'bold' }}>{action.type}</div>
64
- <div style={{ color: '#666', marginTop: '4px' }}>{JSON.stringify(action.payload)}</div>
65
- </div>
66
- ))}
67
- </div>
68
- </section>
69
- </div>
70
- );
71
- }
@@ -1,221 +0,0 @@
1
- import { useState, useEffect } from 'react';
2
- import { flux } from '@minnai/aura/flux/index';
3
- import { Sidebar } from './Sidebar';
4
- import { Debugger } from './Debugger';
5
- import { Space } from '@minnai/aura/controller/Space';
6
- import { CodeEditor } from './CodeEditor';
7
-
8
- export function Playground() {
9
- const [selectedId, setSelectedId] = useState<string | undefined>();
10
- const [editorHeight, setEditorHeight] = useState(350);
11
- const [isResizing, setIsResizing] = useState(false);
12
- const [files, setFiles] = useState<string[]>([]);
13
- const [activeFile, setActiveFile] = useState<string | null>(null);
14
- const [fileContent, setFileContent] = useState<string>('');
15
-
16
- const BUILTIN_AIRS = ['note-taker-air', 'youtube-player-air', 'tasks-air'];
17
-
18
- const handleSelect = async (id: string) => {
19
- setSelectedId(id);
20
- flux.dispatch({ type: 'SPAWN_AIR', payload: { id }, to: 'controller' });
21
-
22
- if (BUILTIN_AIRS.includes(id)) {
23
- setFiles([]);
24
- setActiveFile(null);
25
- setFileContent('');
26
- return;
27
- }
28
-
29
- // Fetch files for this AIR
30
- try {
31
- const res = await fetch(`/api/list-files?airId=${id}`);
32
- const data = await res.json();
33
- setFiles(data.files || []);
34
- if (data.files && data.files.length > 0) {
35
- // Default to index.tsx or first file
36
- const defaultFile = data.files.find((f: string) => f.endsWith('index.tsx')) || data.files[0];
37
- handleFileSelect(defaultFile);
38
- }
39
- } catch (err) {
40
- console.error("Failed to list files:", err);
41
- setFiles([]);
42
- }
43
- };
44
-
45
- const handleFileSelect = async (filePath: string) => {
46
- setActiveFile(filePath);
47
- try {
48
- const url = filePath.startsWith('/') ? filePath : '/' + filePath;
49
- const res = await fetch(url);
50
- if (!res.ok) throw new Error("File not found");
51
- const text = await res.text();
52
- setFileContent(text);
53
- } catch (err) {
54
- console.error("Failed to load file content:", err);
55
- setFileContent("// Error loading file: " + filePath);
56
- }
57
- };
58
-
59
- const handleAddAIR = async () => {
60
- const name = window.prompt("Enter AIR Name (e.g. My Custom Tool):");
61
- if (!name) return;
62
- const id = name.toLowerCase().replace(/\s+/g, '-') + '-air';
63
-
64
- try {
65
- const res = await fetch('/api/scaffold-air', {
66
- method: 'POST',
67
- headers: { 'Content-Type': 'application/json' },
68
- body: JSON.stringify({ airId: id, name })
69
- });
70
- const data = await res.json();
71
- if (data.success) {
72
- alert("Scaffolded successfully! Refreshing...");
73
- window.location.reload();
74
- } else {
75
- alert("Scaffold failed: " + data.error);
76
- }
77
- } catch (err) {
78
- alert("Scaffold error");
79
- }
80
- };
81
-
82
- const handleMouseDown = (e: React.MouseEvent) => {
83
- setIsResizing(true);
84
- e.preventDefault();
85
- };
86
-
87
- useEffect(() => {
88
- const handleMouseMove = (e: MouseEvent) => {
89
- if (!isResizing) return;
90
- const newHeight = window.innerHeight - e.clientY;
91
- setEditorHeight(Math.max(100, Math.min(newHeight, window.innerHeight - 200)));
92
- };
93
- const handleMouseUp = () => setIsResizing(false);
94
- if (isResizing) {
95
- window.addEventListener('mousemove', handleMouseMove);
96
- window.addEventListener('mouseup', handleMouseUp);
97
- }
98
- return () => {
99
- window.removeEventListener('mousemove', handleMouseMove);
100
- window.removeEventListener('mouseup', handleMouseUp);
101
- };
102
- }, [isResizing]);
103
-
104
- const isBuiltIn = selectedId && BUILTIN_AIRS.includes(selectedId);
105
-
106
- return (
107
- <div style={{ display: 'flex', height: 'calc(100vh - 60px)', width: '100vw', overflow: 'hidden' }}>
108
- <div style={{
109
- width: '250px',
110
- height: '100%',
111
- borderRight: '1px solid #ddd',
112
- background: 'white',
113
- display: 'flex',
114
- flexDirection: 'column'
115
- }}>
116
- <Sidebar onSelect={handleSelect} onAddAIR={handleAddAIR} selectedId={selectedId} />
117
- </div>
118
-
119
-
120
- <main style={{ flex: 1, display: 'flex', flexDirection: 'column', background: '#fafafa' }}>
121
- <div style={{ flex: 1, position: 'relative', overflow: 'hidden' }}>
122
- {!selectedId ? (
123
- <div style={{ display: 'flex', height: '100%', alignItems: 'center', justifyContent: 'center', color: '#999' }}>
124
- Select an AIR from the sidebar to begin testing
125
- </div>
126
- ) : (
127
- <Space />
128
- )}
129
- </div>
130
-
131
- {selectedId && (
132
- <div style={{ height: editorHeight, display: 'flex', flexDirection: 'column', borderTop: '1px solid #ddd', position: 'relative', background: '#fff' }}>
133
- <div
134
- onMouseDown={handleMouseDown}
135
- style={{
136
- height: '4px',
137
- width: '100%',
138
- position: 'absolute',
139
- top: '-2px',
140
- cursor: 'ns-resize',
141
- zIndex: 10,
142
- background: isResizing ? '#007aff' : 'transparent',
143
- transition: 'background 0.2s'
144
- }}
145
- />
146
-
147
- <div style={{ display: 'flex', flex: 1, overflow: 'hidden' }}>
148
- {/* File Explorer */}
149
- <div style={{
150
- width: '250px',
151
- borderRight: '1px solid #eee',
152
- background: '#fcfcfc',
153
- display: 'flex',
154
- flexDirection: 'column',
155
- overflowY: 'auto'
156
- }}>
157
- <div style={{ padding: '10px 15px', fontSize: '0.7rem', color: '#999', fontWeight: 600, borderBottom: '1px solid #f0f0f0', textTransform: 'uppercase' }}>
158
- File Explorer
159
- </div>
160
- {isBuiltIn ? (
161
- <div style={{ padding: 20, color: '#999', fontSize: '0.8rem', textAlign: 'center', fontStyle: 'italic' }}>
162
- Built-in Atmosphere AIR
163
- </div>
164
- ) : (
165
- files.map(file => (
166
- <div
167
- key={file}
168
- onClick={() => handleFileSelect(file)}
169
- style={{
170
- padding: '8px 15px',
171
- fontSize: '0.8rem',
172
- cursor: 'pointer',
173
- background: activeFile === file ? '#eef6ff' : 'transparent',
174
- color: activeFile === file ? '#007aff' : '#555',
175
- fontFamily: 'monospace',
176
- textOverflow: 'ellipsis',
177
- whiteSpace: 'nowrap',
178
- overflow: 'hidden',
179
- borderRight: activeFile === file ? '2px solid #007aff' : 'none'
180
- }}
181
- title={file}
182
- >
183
- {file.split(/[\\\/]/).pop()}
184
- </div>
185
- ))
186
- )}
187
- </div>
188
-
189
- {/* Editor */}
190
- <div style={{ flex: 1 }}>
191
- {isBuiltIn ? (
192
- <div style={{ height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center', background: '#1e1e1e', color: '#888', flexDirection: 'column', gap: 10 }}>
193
- <div style={{ fontSize: '2rem' }}>🔒</div>
194
- <div style={{ fontWeight: 600 }}>Built-in Atmosphere AIR</div>
195
- <div style={{ fontSize: '0.8rem', opacity: 0.7 }}>Source code is managed by the main Aura package.</div>
196
- </div>
197
- ) : activeFile ? (
198
- <CodeEditor
199
- airId={selectedId}
200
- filePath={activeFile}
201
- initialCode={fileContent}
202
- />
203
- ) : (
204
- <div style={{ height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center', background: '#f5f5f5', color: '#999' }}>
205
- Select a file to edit
206
- </div>
207
- )}
208
- </div>
209
- </div>
210
- </div>
211
- )}
212
- </main>
213
-
214
- {selectedId && (
215
- <div style={{ width: '300px', borderLeft: '1px solid #ddd', background: 'white', overflowY: 'auto' }}>
216
- <Debugger airId={selectedId} />
217
- </div>
218
- )}
219
- </div>
220
- );
221
- }
@@ -1,68 +0,0 @@
1
- import { EXAMPLE_AIRS } from '../../ambiance';
2
-
3
- interface SidebarProps {
4
- onSelect: (id: string) => void;
5
- onAddAIR: () => void;
6
- selectedId?: string;
7
- }
8
-
9
- export function Sidebar({ onSelect, onAddAIR, selectedId }: SidebarProps) {
10
- return (
11
- <div style={{
12
- flex: 1,
13
- padding: '20px',
14
- display: 'flex',
15
- flexDirection: 'column',
16
- gap: '10px',
17
- overflowY: 'auto'
18
- }}>
19
- <h3 style={{ margin: '0 0 10px 0', fontSize: '0.9rem', color: '#666', textTransform: 'uppercase', letterSpacing: '0.05em' }}>
20
- Available AIRs
21
- </h3>
22
- <div style={{ display: 'flex', flexDirection: 'column', gap: '8px', flex: 1 }}>
23
- {EXAMPLE_AIRS.map(air => (
24
- <button
25
- key={air.id}
26
- onClick={() => onSelect(air.id)}
27
- style={{
28
- padding: '12px 15px',
29
- textAlign: 'left',
30
- borderRadius: '8px',
31
- border: selectedId === air.id ? '1px solid #007aff' : '1px solid #eee',
32
- background: selectedId === air.id ? '#f0f7ff' : 'white',
33
- color: selectedId === air.id ? '#007aff' : '#1d1d1f',
34
- cursor: 'pointer',
35
- fontSize: '0.9rem',
36
- fontWeight: selectedId === air.id ? '600' : '400',
37
- transition: 'all 0.2s ease'
38
- }}
39
- >
40
- {typeof air.meta.title === 'function' ? air.meta.title('en') : air.meta.title}
41
- </button>
42
- ))}
43
- </div>
44
-
45
- <button
46
- onClick={onAddAIR}
47
- style={{
48
- marginTop: '20px',
49
- padding: '12px',
50
- background: '#007aff',
51
- color: 'white',
52
- border: 'none',
53
- borderRadius: 8,
54
- cursor: 'pointer',
55
- fontSize: '0.85rem',
56
- fontWeight: 600,
57
- display: 'flex',
58
- alignItems: 'center',
59
- justifyContent: 'center',
60
- gap: '8px',
61
- boxShadow: '0 2px 8px rgba(0,122,255,0.2)'
62
- }}
63
- >
64
- <span>+</span> Add Custom AIR
65
- </button>
66
- </div>
67
- );
68
- }