-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcomponent.html
More file actions
48 lines (45 loc) · 12.2 KB
/
component.html
File metadata and controls
48 lines (45 loc) · 12.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Dynamic Component Page</title>
<!-- Load React and ReactDOM from CDN -->
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
</head>
<body>
<div id="root"></div>
<!-- Embed the component data safely as JSON -->
<script id="component-data" type="application/json">
{"name": "ToolWrapper", "props": {"toolName": "gmail", "children": {"name": "GmailMessageCard", "props": {"data": {"id": "1955ba35636a2f90", "thread_id": "1955ba35636a2f90", "subject": "Demo", "snippet": "Hello World!", "body": "Hello World!", "recipient": "hello@veyrax.com", "sender": "veyraxservice@gmail.com", "date": "2025-03-03T05:53:06-05:00", "html_link": "https://mail.google.com/mail/u/0/#inbox/1955ba35636a2f90", "labels": ["DRAFT"], "draft_id": "r8957220012029385417"}}, "jsx": "function GmailMessageCard(props) {\n const message = props.data;\n if (!message) return null;\n\n const formatDate = (dateStr) => {\n if (!dateStr) return '';\n const date = new Date(dateStr);\n if (date.toString() === 'Invalid Date') return '';\n return date.toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit'\n });\n };\n\n // Link icon SVG\n function LinkIcon() {\n return React.createElement('svg', {\n width: '10',\n height: '10',\n viewBox: '0 0 16 16',\n fill: 'none',\n style: { color: '#64748b' }\n }, [\n React.createElement('path', {\n key: 'p1',\n d: 'M6.5 9.5L9.5 6.5',\n stroke: 'currentColor',\n strokeWidth: '1.5',\n strokeLinecap: 'round',\n strokeLinejoin: 'round'\n }),\n React.createElement('path', {\n key: 'p2',\n d: 'M4.5 7.5L3 9C2.17157 9.82843 2.17157 11.1716 3 12C3.82843 12.8284 5.17157 12.8284 6 12L7.5 10.5',\n stroke: 'currentColor',\n strokeWidth: '1.5',\n strokeLinecap: 'round',\n strokeLinejoin: 'round'\n }),\n React.createElement('path', {\n key: 'p3',\n d: 'M8.5 5.5L10 4C10.8284 3.17157 12.1716 3.17157 13 4C13.8284 4.82843 13.8284 6.17157 13 7L11.5 8.5',\n stroke: 'currentColor',\n strokeWidth: '1.5',\n strokeLinecap: 'round',\n strokeLinejoin: 'round'\n })\n ]);\n }\n\n // \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043b\u0438 data \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c MessageList \u0438\u043b\u0438 Message\n const isMessageList = message.messages !== undefined;\n const messageData = isMessageList ? message.messages : [message];\n \n const containerStyles = {\n display: 'flex',\n flexWrap: 'wrap',\n gap: '12px',\n width: '100%'\n };\n \n // \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0438 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 \u0441\u0435\u0442\u043a\u0435\n return React.createElement('div', { style: containerStyles },\n messageData.map((messageItem, index) => {\n const formattedDate = formatDate(messageItem.date);\n\n const cardStyle = {\n position: 'relative',\n borderRadius: '8px',\n border: '1px solid #e2e8f0',\n backgroundColor: '#ffffff',\n padding: '8px 12px',\n marginBottom: '8px',\n width: 'calc(50% - 6px)',\n minWidth: '250px',\n boxSizing: 'border-box'\n };\n \n const flexContainerStyle = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: '8px'\n };\n \n const contentStyle = {\n minWidth: 0,\n flex: 1\n };\n \n const titleContainerStyle = {\n display: 'flex',\n alignItems: 'center',\n gap: '2px'\n };\n \n const titleStyle = {\n fontWeight: '500',\n color: '#1e293b',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n fontSize: '14px',\n margin: 0\n };\n \n const infoStyle = {\n fontSize: '12px',\n color: '#64748b',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n marginTop: '4px',\n margin: 0\n };\n \n const linkStyle = {\n color: '#64748b',\n display: 'flex',\n alignItems: 'center',\n marginRight: '4px',\n textDecoration: 'none',\n flexShrink: 0\n };\n \n const snippetStyle = {\n fontSize: '12px',\n color: '#64748b',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n display: '-webkit-box',\n WebkitLineClamp: 2,\n WebkitBoxOrient: 'vertical',\n marginTop: '8px'\n };\n\n return React.createElement('div', { key: messageItem.id, style: cardStyle },\n React.createElement('div', { style: flexContainerStyle },\n React.createElement('div', { style: contentStyle },\n React.createElement('div', { style: titleContainerStyle },\n messageItem.html_link && React.createElement('a', {\n href: messageItem.html_link,\n target: '_blank',\n rel: 'noopener noreferrer',\n style: linkStyle\n }, React.createElement(LinkIcon)),\n React.createElement('h3', { style: titleStyle }, messageItem.subject || '(No Subject)')\n ),\n React.createElement('p', { style: infoStyle },\n `To: ${messageItem.recipient || 'Unknown'}, ${formattedDate}`\n )\n )\n ),\n React.createElement('div', { style: snippetStyle }, messageItem.snippet)\n );\n })\n );\n}"}}, "jsx": "function ToolWrapper(props) {\n const [isExpanded, setIsExpanded] = React.useState(true);\n const { toolName, children } = props;\n \n const TOOL_CONFIGS = {\n gmail: {\n logo: '\ud83d\udce7',\n label: 'Gmail',\n },\n 'google-calendar': {\n logo: '\ud83d\udcc5',\n label: 'Google Calendar',\n },\n notion: {\n logo: '\ud83d\udcdd',\n label: 'Notion',\n },\n stripe: {\n logo: '\ud83d\udcb3',\n label: 'Stripe',\n },\n openweather: {\n logo: '\ud83c\udf24\ufe0f',\n label: 'OpenWeather',\n },\n perplexity: {\n logo: '\ud83d\udd0d',\n label: 'Perplexity',\n },\n 'google-drive': {\n logo: '\ud83d\udcc1',\n label: 'Google Drive',\n },\n linear: {\n logo: '\ud83d\udcca',\n label: 'Linear',\n },\n confluence: {\n logo: '\ud83d\udcc4',\n label: 'Confluence',\n },\n jira: {\n logo: '\ud83c\udfab',\n label: 'Jira',\n },\n outlook: {\n logo: '\u2709\ufe0f',\n label: 'Outlook',\n },\n };\n\n const toolConfig = TOOL_CONFIGS[toolName] || { logo: '\ud83d\udd27', label: toolName };\n \n const styles = {\n container: {\n border: '1px solid #e2e8f0',\n borderRadius: '8px',\n overflow: 'hidden',\n marginBottom: '16px',\n fontFamily: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif',\n width: '100%',\n },\n header: {\n display: 'flex',\n alignItems: 'center',\n padding: '8px 12px',\n backgroundColor: '#f8fafc',\n cursor: 'pointer',\n borderBottom: isExpanded ? '1px solid #e2e8f0' : 'none',\n width: '100%',\n },\n chevron: {\n marginRight: '8px',\n fontSize: '14px',\n transition: 'transform 0.2s',\n },\n logoContainer: {\n marginRight: '8px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: '16px',\n },\n label: {\n fontWeight: '500',\n fontSize: '14px',\n },\n content: {\n padding: isExpanded ? '16px' : '0',\n height: isExpanded ? 'auto' : '0',\n overflow: 'hidden',\n transition: 'height 0.2s ease, padding 0.2s ease',\n width: '100%',\n },\n componentsContainer: {\n display: 'flex',\n flexWrap: 'wrap',\n gap: '16px',\n width: '100%',\n }\n };\n \n // \u0421\u043e\u0437\u0434\u0430\u0435\u043c ref \u0434\u043b\u044f \u0438\u0437\u043c\u0435\u0440\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430\n const contentRef = React.useRef(null);\n \n // \u0420\u0435\u043d\u0434\u0435\u0440\u0438\u043c \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b\n const renderChildren = () => {\n if (!children) return null;\n \n // \u0415\u0441\u043b\u0438 children - \u044d\u0442\u043e \u043c\u0430\u0441\u0441\u0438\u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432\n if (Array.isArray(children)) {\n return React.createElement('div', { style: styles.componentsContainer },\n children.map((child, index) => {\n if (!child.jsx) return null;\n \n try {\n const ChildComponent = new Function(\n 'React', \n 'props', \n `const Comp = ${child.jsx}; return Comp(props);`\n );\n return React.createElement('div', { key: index }, ChildComponent(React, child.props));\n } catch (error) {\n console.error('Error rendering child component:', error);\n return React.createElement('div', { key: index }, 'Error rendering component');\n }\n })\n );\n }\n \n // \u0415\u0441\u043b\u0438 children - \u044d\u0442\u043e \u043e\u0434\u0438\u043d \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0441 jsx\n if (children.jsx) {\n try {\n const ChildComponent = new Function(\n 'React', \n 'props', \n `const Comp = ${children.jsx}; return Comp(props);`\n );\n return ChildComponent(React, children.props);\n } catch (error) {\n console.error('Error rendering child component:', error);\n return React.createElement('div', {}, 'Error rendering component');\n }\n }\n \n // \u0415\u0441\u043b\u0438 \u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e React \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0438\u043b\u0438 \u0442\u0435\u043a\u0441\u0442\n return children;\n };\n \n return React.createElement('div', { style: styles.container },\n React.createElement('div', { \n style: styles.header,\n onClick: () => setIsExpanded(!isExpanded)\n },\n React.createElement('span', { style: styles.chevron }, isExpanded ? '\u25bc' : '\u25b6'),\n React.createElement('div', { style: styles.logoContainer }, toolConfig.logo),\n React.createElement('span', { style: styles.label }, toolConfig.label)\n ),\n React.createElement('div', { \n ref: contentRef,\n style: styles.content \n }, renderChildren())\n );\n}"}
</script>
<script type="text/javascript">
// Retrieve and parse the component data
const components = JSON.parse(document.getElementById('component-data').textContent);
// Function to create a dynamic component from its specification.
// It uses new Function to evaluate the provided JSX code and then returns the component function.
function createComponent(comp) {
try {
const factory = new Function('React', 'props', `
${comp.jsx}
return ${comp.name};
`);
return factory(React, comp.props);
} catch (error) {
console.error('Error creating component:', error);
return function() {
return React.createElement('div', null, 'Error rendering component');
};
}
}
// For this example, assume there is only one component in the list.
const comp = components;
const DynamicComponent = createComponent(comp);
// Render the dynamic component into the #root element.
ReactDOM.render(
React.createElement(DynamicComponent, comp.props),
document.getElementById('root')
);
</script>
</body>
</html>