super-productivity/packages/plugin-dev/api-test-plugin/index.html
felix bear 71f4ca484c
fix(plugins): return dialog result #5239 (#8106)
Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 12:14:08 +02:00

897 lines
34 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>API Test Plugin Dashboard</title>
<style>
/* Theme vars + UI Kit are injected automatically.
Only layout rules that the UI Kit can't provide. */
body {
padding: var(--s3);
}
.button-grid {
display: flex;
flex-wrap: wrap;
gap: var(--s);
}
.api-list {
display: flex;
flex-wrap: wrap;
gap: var(--s-half);
}
.console {
max-height: 200px;
overflow-y: auto;
}
.console-entry.success {
color: var(--color-success);
}
.console-entry.error {
color: var(--color-danger);
}
.console-entry.info {
color: var(--text-color-muted);
}
</style>
</head>
<body>
<h1>API Test Plugin</h1>
<h3>Available API Methods</h3>
<p class="api-list">
<code>getTasks()</code>
<code>getArchivedTasks()</code>
<code>getCurrentContextTasks()</code>
<code>addTask(data)</code>
<code>updateTask(id, data)</code>
<code>getAllProjects()</code>
<code>addProject(data)</code>
<code>updateProject(id, data)</code>
<code>getAllTags()</code>
<code>addTag(data)</code>
<code>updateTag(id, data)</code>
<code>showSnack(config)</code>
<code>notify(config)</code>
<code>openDialog(config)</code>
<code>persistDataSynced(data)</code>
<code>loadSyncedData()</code>
<code>registerHook(hook, handler)</code>
<code>registerHeaderButton(config)</code>
<code>registerMenuEntry(config)</code>
<code>registerShortcut(config)</code>
<code>setCounter(key, value)</code>
<code>getCounter(key)</code>
<code>incrementCounter(key, amount)</code>
<code>decrementCounter(key, amount)</code>
<code>deleteCounter(key)</code>
<code>getAllCounters()</code>
</p>
<hr />
<button onclick="runAllTests()">Run All API Tests</button>
<hr />
<h2>Data Persistence Tests</h2>
<div class="button-grid">
<button onclick="testPersistData()">Test Save Data</button>
<button onclick="testLoadData()">Test Load Data</button>
</div>
<h2>Task Operations</h2>
<div class="button-grid">
<button onclick="testGetTasks()">Get All Tasks</button>
<button onclick="testGetArchivedTasks()">Get Archived Tasks</button>
<button onclick="testGetContextTasks()">Get Context Tasks</button>
<button onclick="testCreateTask()">Create Test Task</button>
<button onclick="testUpdateTask()">Update Last Task</button>
</div>
<h2>Project &amp; Tag Operations</h2>
<div class="button-grid">
<button onclick="testGetProjects()">Get All Projects</button>
<button onclick="testCreateProject()">Create Test Project</button>
<button onclick="testGetTags()">Get All Tags</button>
<button onclick="testCreateTag()">Create Test Tag</button>
</div>
<h2>UI Operations</h2>
<div class="button-grid">
<button onclick="testSnackSuccess()">Success Snack</button>
<button onclick="testSnackError()">Error Snack</button>
<button onclick="testSnackCustom()">Info Snack</button>
<button onclick="testNotification()">Show Notification</button>
<button onclick="testDialog()">Open Dialog</button>
</div>
<h2>Advanced Dialog Examples</h2>
<div class="button-grid">
<button onclick="showTaskPlannerDialog()">Task Planner</button>
<button onclick="showAnalyticsDialog()">Analytics Dashboard</button>
</div>
<pre
class="console"
id="console"
><span class="console-entry info">Console output will appear here...</span></pre>
<hr />
<h2>UI Kit Component Showcase</h2>
<h3>Headings</h3>
<h1>Heading 1</h1>
<h2>Heading 2</h2>
<h3>Heading 3</h3>
<h4>Heading 4</h4>
<h5>Heading 5</h5>
<h6>Heading 6</h6>
<h3>Text</h3>
<p>
This is a paragraph with <strong>bold</strong>, <em>italic</em>, and
<a href="#">link</a> styles.
</p>
<p>Inline <code>code</code> is styled automatically.</p>
<h3>Buttons</h3>
<div class="button-grid">
<button>Default</button>
<button class="btn-primary">Primary</button>
<button class="btn-outline">Outline</button>
<button disabled>Disabled</button>
<button
class="btn-primary"
disabled
>
Primary Disabled
</button>
<button
class="btn-outline"
disabled
>
Outline Disabled
</button>
</div>
<h3>Inputs</h3>
<input
type="text"
placeholder="Text input"
/>
<textarea placeholder="Textarea"></textarea>
<select>
<option>Select option 1</option>
<option>Select option 2</option>
<option>Select option 3</option>
</select>
<label><input type="checkbox" /> Checkbox label</label>
<h3>Code Block</h3>
<pre><code>const tasks = await PluginAPI.getTasks();
console.log(tasks.length);</code></pre>
<h3>Table</h3>
<table>
<thead>
<tr>
<th>Method</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>getTasks()</code></td>
<td>Get all active tasks</td>
</tr>
<tr>
<td><code>addTask(data)</code></td>
<td>Create a new task</td>
</tr>
<tr>
<td><code>showSnack(cfg)</code></td>
<td>Show a notification</td>
</tr>
</tbody>
</table>
<h3>Lists</h3>
<ul>
<li>Unordered list item 1</li>
<li>Unordered list item 2</li>
<li>Unordered list item 3</li>
</ul>
<ol>
<li>Ordered list item 1</li>
<li>Ordered list item 2</li>
<li>Ordered list item 3</li>
</ol>
<h3>Cards</h3>
<div class="card">
<h4>Default Card</h4>
<p>A static card with background, shadow, and border.</p>
</div>
<br />
<div class="card card-clickable">
<h4>Clickable Card</h4>
<p>Hover to see the lift effect and primary border highlight.</p>
</div>
<h3>Horizontal Rule</h3>
<hr />
<script>
let lastTaskId = null;
let lastProjectId = null;
let lastTagId = null;
// Console logging
function log(message, type = 'info') {
const con = document.getElementById('console');
const entry = document.createElement('span');
entry.className = `console-entry ${type}`;
entry.textContent = `[${new Date().toLocaleTimeString()}] ${message}\n`;
con.appendChild(entry);
con.scrollTop = con.scrollHeight;
}
// Clear console
function clearConsole() {
document.getElementById('console').innerHTML =
'<span class="console-entry info">Console cleared. Starting new test run...\n</span>';
}
// Test functions
async function testPersistData() {
try {
const testData = {
timestamp: new Date().toISOString(),
randomValue: Math.floor(Math.random() * 1000),
message: 'Test data from iframe',
};
await PluginAPI.persistDataSynced(JSON.stringify(testData));
log('Data saved successfully: ' + JSON.stringify(testData), 'success');
} catch (error) {
log('Failed to save data: ' + error.message, 'error');
}
}
async function testLoadData() {
try {
const data = await PluginAPI.loadSyncedData();
if (data) {
const parsed = JSON.parse(data);
log('Data loaded successfully: ' + JSON.stringify(parsed), 'success');
} else {
log('No saved data found', 'info');
}
} catch (error) {
log('Failed to load data: ' + error.message, 'error');
}
}
async function testGetTasks() {
try {
const tasks = await PluginAPI.getTasks();
log(`Found ${tasks.length} tasks`, 'success');
if (tasks.length > 0) {
lastTaskId = tasks[0].id;
log(`Sample task: "${tasks[0].title}"`, 'info');
}
} catch (error) {
log('Failed to get tasks: ' + error.message, 'error');
}
}
async function testGetArchivedTasks() {
try {
const tasks = await PluginAPI.getArchivedTasks();
log(`Found ${tasks.length} archived tasks`, 'success');
} catch (error) {
log('Failed to get archived tasks: ' + error.message, 'error');
}
}
async function testGetContextTasks() {
try {
const tasks = await PluginAPI.getCurrentContextTasks();
log(`Found ${tasks.length} tasks in current context`, 'success');
} catch (error) {
log('Failed to get context tasks: ' + error.message, 'error');
}
}
async function testCreateTask() {
try {
const taskData = {
title: 'Test Task from iFrame - ' + new Date().toLocaleTimeString(),
notes: 'Created from the API Test Plugin dashboard',
timeEstimate: 1800000, // 30 minutes
};
lastTaskId = await PluginAPI.addTask(taskData);
log(`Task created with ID: ${lastTaskId}`, 'success');
} catch (error) {
log('Failed to create task: ' + error.message, 'error');
}
}
async function testUpdateTask() {
if (!lastTaskId) {
log('No task ID available. Create a task first!', 'error');
return;
}
try {
await PluginAPI.updateTask(lastTaskId, {
notes: 'Updated from dashboard at ' + new Date().toLocaleTimeString(),
});
log(`Task ${lastTaskId} updated successfully`, 'success');
} catch (error) {
log('Failed to update task: ' + error.message, 'error');
}
}
async function testGetProjects() {
try {
const projects = await PluginAPI.getAllProjects();
log(`Found ${projects.length} projects`, 'success');
if (projects.length > 0) {
lastProjectId = projects[0].id;
log(`Sample project: "${projects[0].title}"`, 'info');
}
} catch (error) {
log('Failed to get projects: ' + error.message, 'error');
}
}
async function testCreateProject() {
try {
const project = await PluginAPI.addProject({
title: 'Test Project - ' + new Date().toLocaleDateString(),
themeColor: '#' + Math.floor(Math.random() * 16777215).toString(16),
});
lastProjectId = project.id;
log(`Project created: "${project.title}"`, 'success');
} catch (error) {
log('Failed to create project: ' + error.message, 'error');
}
}
// Counter test functions
async function testSetCounter() {
try {
const value = Math.floor(Math.random() * 100);
await PluginAPI.setCounter('testCounter', value);
log(`Counter 'testCounter' set to ${value}`, 'success');
} catch (error) {
log('Failed to set counter: ' + error.message, 'error');
}
}
async function testGetCounter() {
try {
const value = await PluginAPI.getCounter('testCounter');
if (value !== null) {
log(`Counter 'testCounter' value: ${value}`, 'success');
} else {
log("Counter 'testCounter' not found", 'info');
}
} catch (error) {
log('Failed to get counter: ' + error.message, 'error');
}
}
async function testIncrementCounter() {
try {
const newValue = await PluginAPI.incrementCounter('testCounter', 5);
log(
`Counter 'testCounter' incremented by 5, new value: ${newValue}`,
'success',
);
} catch (error) {
log('Failed to increment counter: ' + error.message, 'error');
}
}
async function testDecrementCounter() {
try {
const newValue = await PluginAPI.decrementCounter('testCounter', 3);
log(
`Counter 'testCounter' decremented by 3, new value: ${newValue}`,
'success',
);
} catch (error) {
log('Failed to decrement counter: ' + error.message, 'error');
}
}
async function testDeleteCounter() {
try {
await PluginAPI.deleteCounter('testCounter');
log("Counter 'testCounter' deleted", 'success');
} catch (error) {
log('Failed to delete counter: ' + error.message, 'error');
}
}
async function testGetAllCounters() {
try {
// Create some test counters first
await PluginAPI.setCounter('counter1', 10);
await PluginAPI.setCounter('counter2', 20);
await PluginAPI.setCounter('counter3', 30);
const counters = await PluginAPI.getAllCounters();
log('All counters: ' + JSON.stringify(counters), 'success');
} catch (error) {
log('Failed to get all counters: ' + error.message, 'error');
}
}
async function testGetTags() {
try {
const tags = await PluginAPI.getAllTags();
log(`Found ${tags.length} tags`, 'success');
if (tags.length > 0) {
lastTagId = tags[0].id;
log(`Sample tag: "${tags[0].title}"`, 'info');
}
} catch (error) {
log('Failed to get tags: ' + error.message, 'error');
}
}
async function testCreateTag() {
try {
const tag = await PluginAPI.addTag({
title: 'Test Tag - ' + Date.now(),
color: '#' + Math.floor(Math.random() * 16777215).toString(16),
});
lastTagId = tag.id;
log(`Tag created: "${tag.title}"`, 'success');
} catch (error) {
log('Failed to create tag: ' + error.message, 'error');
}
}
function testSnackSuccess() {
PluginAPI.showSnack({
msg: 'This is a success message',
type: 'SUCCESS',
ico: 'check_circle',
});
log('Success snack shown', 'success');
}
function testSnackError() {
PluginAPI.showSnack({
msg: 'This is an error message',
type: 'ERROR',
ico: 'error',
});
log('Error snack shown', 'success');
}
function testSnackCustom() {
PluginAPI.showSnack({
msg: 'This is an info message',
type: 'INFO',
ico: 'info',
});
log('Info snack shown', 'success');
}
function testNotification() {
PluginAPI.notify({
title: 'API Test Notification',
body: 'This notification was triggered from the plugin dashboard!',
});
log('Notification sent', 'success');
}
async function testDialog() {
const result = await PluginAPI.openDialog({
title: 'Test Dialog from iFrame',
htmlContent: `
<div style="padding: 20px; color: #ccc; font-family: monospace;">
<h3 style="margin: 0 0 10px 0; font-size: 14px;">Test Dialog</h3>
<p style="margin: 5px 0; font-size: 12px;">Dialog opened from plugin dashboard</p>
<p style="margin: 5px 0; font-size: 12px; color: #999;">${new Date().toLocaleString()}</p>
</div>
`,
buttons: [
{
label: 'Awesome',
icon: 'thumb_up',
color: 'primary',
onClick: () => {
log('Dialog button clicked', 'success');
},
},
],
});
log('Dialog closed with result: ' + result, 'success');
}
function testThemeInfo() {
try {
const themeInfo = PluginAPI.getThemeInfo();
log('Theme Info:', 'info');
log(' Dark Theme: ' + themeInfo.isDarkTheme, 'info');
log(' Primary Color: ' + themeInfo.primaryColor, 'info');
log(' Accent Color: ' + themeInfo.accentColor, 'info');
log(' Warn Color: ' + themeInfo.warnColor, 'info');
log(' Background: ' + themeInfo.backgroundColor, 'info');
log(' Text Color: ' + themeInfo.textColor, 'info');
// Also show in a dialog
PluginAPI.openDialog({
title: 'Current Theme Information',
htmlContent: `
<div style="padding: 20px; font-family: monospace;">
<h3 style="margin: 0 0 15px 0;">Theme Variables</h3>
<table style="width: 100%; border-collapse: collapse;">
<tr style="border-bottom: 1px solid var(--divider-color, #333);">
<td style="padding: 8px;">Dark Theme</td>
<td style="padding: 8px; text-align: right;">${themeInfo.isDarkTheme ? 'Yes' : 'No'}</td>
</tr>
<tr style="border-bottom: 1px solid var(--divider-color, #333);">
<td style="padding: 8px;">Primary Color</td>
<td style="padding: 8px; text-align: right;">
<span style="display: inline-block; width: 20px; height: 20px; background: ${themeInfo.primaryColor}; vertical-align: middle; margin-right: 8px; border: 1px solid var(--divider-color, #333);"></span>
${themeInfo.primaryColor}
</td>
</tr>
<tr style="border-bottom: 1px solid var(--divider-color, #333);">
<td style="padding: 8px;">Accent Color</td>
<td style="padding: 8px; text-align: right;">
<span style="display: inline-block; width: 20px; height: 20px; background: ${themeInfo.accentColor}; vertical-align: middle; margin-right: 8px; border: 1px solid var(--divider-color, #333);"></span>
${themeInfo.accentColor}
</td>
</tr>
<tr style="border-bottom: 1px solid var(--divider-color, #333);">
<td style="padding: 8px;">Warn Color</td>
<td style="padding: 8px; text-align: right;">
<span style="display: inline-block; width: 20px; height: 20px; background: ${themeInfo.warnColor}; vertical-align: middle; margin-right: 8px; border: 1px solid var(--divider-color, #333);"></span>
${themeInfo.warnColor}
</td>
</tr>
<tr style="border-bottom: 1px solid var(--divider-color, #333);">
<td style="padding: 8px;">Background</td>
<td style="padding: 8px; text-align: right;">
<span style="display: inline-block; width: 20px; height: 20px; background: ${themeInfo.backgroundColor}; vertical-align: middle; margin-right: 8px; border: 1px solid var(--divider-color, #333);"></span>
${themeInfo.backgroundColor}
</td>
</tr>
<tr>
<td style="padding: 8px;">Text Color</td>
<td style="padding: 8px; text-align: right;">
<span style="display: inline-block; width: 20px; height: 20px; background: ${themeInfo.textColor}; vertical-align: middle; margin-right: 8px; border: 1px solid var(--divider-color, #333);"></span>
${themeInfo.textColor}
</td>
</tr>
</table>
<p style="margin-top: 15px; font-size: 12px; color: var(--text-color-muted, #999);">
Plugins automatically receive all CSS variables from the host application, allowing seamless theme integration.
</p>
</div>
`,
buttons: [
{
label: 'Close',
color: 'primary',
},
],
});
} catch (error) {
log('Failed to get theme info: ' + error.message, 'error');
}
}
async function runAllTests() {
clearConsole();
log('Starting comprehensive API test suite...', 'info');
// Run all tests with delays
await testPersistData();
await new Promise((r) => setTimeout(r, 500));
await testLoadData();
await new Promise((r) => setTimeout(r, 500));
await testGetTasks();
await new Promise((r) => setTimeout(r, 500));
await testGetArchivedTasks();
await new Promise((r) => setTimeout(r, 500));
await testGetContextTasks();
await new Promise((r) => setTimeout(r, 500));
await testCreateTask();
await new Promise((r) => setTimeout(r, 500));
if (lastTaskId) {
await testUpdateTask();
await new Promise((r) => setTimeout(r, 500));
}
await testGetProjects();
await new Promise((r) => setTimeout(r, 500));
await testCreateProject();
await new Promise((r) => setTimeout(r, 500));
await testGetTags();
await new Promise((r) => setTimeout(r, 500));
await testCreateTag();
await new Promise((r) => setTimeout(r, 500));
// Test counter API
await testSetCounter();
await new Promise((r) => setTimeout(r, 500));
await testGetCounter();
await new Promise((r) => setTimeout(r, 500));
await testIncrementCounter();
await new Promise((r) => setTimeout(r, 500));
await testDecrementCounter();
await new Promise((r) => setTimeout(r, 500));
await testGetAllCounters();
await new Promise((r) => setTimeout(r, 500));
testSnackSuccess();
await new Promise((r) => setTimeout(r, 1500));
testSnackError();
await new Promise((r) => setTimeout(r, 1500));
testSnackCustom();
await new Promise((r) => setTimeout(r, 1500));
testNotification();
await new Promise((r) => setTimeout(r, 1000));
testDialog();
log('All tests completed! Check console for detailed results.', 'success');
}
// Advanced Dialog Examples
function showTaskPlannerDialog() {
PluginAPI.openDialog({
title: 'AI Task Planner (Demo)',
htmlContent: `
<div style="padding: 20px; max-width: 700px;">
<div style="display: flex; gap: 20px;">
<div style="flex: 1;">
<h4 style="margin-top: 0;">Describe Your Goal</h4>
<textarea style="width: 100%; min-height: 100px; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-family: inherit;" placeholder="E.g., 'Launch a new mobile app by Q3 2024'">Build a comprehensive plugin system for Super Productivity that allows users to extend functionality</textarea>
<h4 style="margin-top: 20px;">Constraints & Preferences</h4>
<div style="margin-bottom: 10px;">
<label>
<input type="checkbox" checked> Break down into weekly milestones
</label>
</div>
<div style="margin-bottom: 10px;">
<label>
<input type="checkbox" checked> Include time estimates
</label>
</div>
<div style="margin-bottom: 10px;">
<label>
<input type="checkbox"> Add dependencies between tasks
</label>
</div>
<div style="margin-bottom: 10px;">
<label>
<input type="checkbox" checked> Prioritize by impact
</label>
</div>
</div>
<div style="flex: 1; background: #f9f9f9; padding: 15px; border-radius: 8px;">
<h4 style="margin-top: 0;">Generated Task Breakdown</h4>
<div style="max-height: 300px; overflow-y: auto;">
<div style="margin-bottom: 15px; padding: 10px; background: white; border-radius: 4px; border-left: 4px solid #4caf50;">
<div style="font-weight: bold;">📋 Design Plugin Architecture</div>
<div style="font-size: 0.9em; color: #666; margin-top: 5px;">Est: 8h | Priority: High</div>
<div style="font-size: 0.85em; margin-top: 5px;">Define API surface, security model, and manifest structure</div>
</div>
<div style="margin-bottom: 15px; padding: 10px; background: white; border-radius: 4px; border-left: 4px solid #ff9800;">
<div style="font-weight: bold;">🔧 Implement Core Plugin Loader</div>
<div style="font-size: 0.9em; color: #666; margin-top: 5px;">Est: 16h | Priority: High</div>
<div style="font-size: 0.85em; margin-top: 5px;">Build sandboxed execution environment and API bridge</div>
</div>
<div style="margin-bottom: 15px; padding: 10px; background: white; border-radius: 4px; border-left: 4px solid #2196f3;">
<div style="font-weight: bold;">🎨 Create Plugin UI Components</div>
<div style="font-size: 0.9em; color: #666; margin-top: 5px;">Est: 12h | Priority: Medium</div>
<div style="font-size: 0.85em; margin-top: 5px;">Design settings UI, permission dialogs, and plugin store</div>
</div>
<div style="margin-bottom: 15px; padding: 10px; background: white; border-radius: 4px; border-left: 4px solid #9c27b0;">
<div style="font-weight: bold;">📚 Write Documentation</div>
<div style="font-size: 0.9em; color: #666; margin-top: 5px;">Est: 6h | Priority: Medium</div>
<div style="font-size: 0.85em; margin-top: 5px;">Create plugin development guide and API reference</div>
</div>
</div>
</div>
</div>
<div style="margin-top: 20px; padding: 15px; background: #fff3cd; border: 1px solid #ffeaa7; border-radius: 4px;">
<strong>🤖 AI Analysis:</strong> This project would take approximately 42 hours (5-6 days) with the current breakdown. Consider adding a testing phase and security audit.
</div>
</div>
`,
buttons: [
{
label: 'Regenerate',
icon: 'refresh',
onClick: async () => {
await PluginAPI.showSnack({
msg: 'Regenerating task breakdown...',
type: 'INFO',
ico: 'refresh',
});
},
},
{
label: 'Create All Tasks',
icon: 'add_task',
color: 'primary',
onClick: async () => {
await PluginAPI.showSnack({
msg: 'Would create 4 tasks in your project',
type: 'SUCCESS',
});
},
},
],
});
log('Task planner dialog opened', 'success');
}
function showAnalyticsDialog() {
PluginAPI.openDialog({
title: 'Productivity Analytics',
htmlContent: `
<div style="padding: 20px; max-width: 800px;">
<div style="display: flex; justify-content: space-between; margin-bottom: 20px;">
<div>
<h3 style="margin: 0;">Weekly Performance</h3>
<p style="margin: 5px 0; color: #666;">Dec 11 - Dec 17, 2023</p>
</div>
<div style="display: flex; gap: 10px; align-items: center;">
<button style="padding: 8px 16px; border: 1px solid #ddd; background: white; border-radius: 4px; cursor: pointer;">Week</button>
<button style="padding: 8px 16px; border: 1px solid #4caf50; background: #4caf50; color: white; border-radius: 4px; cursor: pointer;">Month</button>
<button style="padding: 8px 16px; border: 1px solid #ddd; background: white; border-radius: 4px; cursor: pointer;">Year</button>
</div>
</div>
<div style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 15px; margin-bottom: 30px;">
<div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px; border-radius: 8px;">
<div style="font-size: 2em; font-weight: bold;">147</div>
<div style="opacity: 0.9;">Tasks Completed</div>
<div style="font-size: 0.9em; margin-top: 5px; opacity: 0.8;">↑ 23% from last week</div>
</div>
<div style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); color: white; padding: 20px; border-radius: 8px;">
<div style="font-size: 2em; font-weight: bold;">42.5h</div>
<div style="opacity: 0.9;">Time Tracked</div>
<div style="font-size: 0.9em; margin-top: 5px; opacity: 0.8;">↑ 5% from last week</div>
</div>
<div style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); color: white; padding: 20px; border-radius: 8px;">
<div style="font-size: 2em; font-weight: bold;">89%</div>
<div style="opacity: 0.9;">Focus Score</div>
<div style="font-size: 0.9em; margin-top: 5px; opacity: 0.8;">↓ 2% from last week</div>
</div>
<div style="background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%); color: white; padding: 20px; border-radius: 8px;">
<div style="font-size: 2em; font-weight: bold;">12</div>
<div style="opacity: 0.9;">Streaks Active</div>
<div style="font-size: 0.9em; margin-top: 5px; opacity: 0.8;">Keep it up! 🔥</div>
</div>
</div>
<div style="background: #f9f9f9; padding: 20px; border-radius: 8px;">
<h4 style="margin-top: 0;">Daily Activity Heatmap</h4>
<div style="display: grid; grid-template-columns: auto repeat(7, 1fr); gap: 10px; font-size: 0.9em;">
<div></div>
<div style="text-align: center;">Mon</div>
<div style="text-align: center;">Tue</div>
<div style="text-align: center;">Wed</div>
<div style="text-align: center;">Thu</div>
<div style="text-align: center;">Fri</div>
<div style="text-align: center;">Sat</div>
<div style="text-align: center;">Sun</div>
<div>Morning</div>
<div style="background: #c8e6c9; height: 40px; border-radius: 4px;"></div>
<div style="background: #4caf50; height: 40px; border-radius: 4px;"></div>
<div style="background: #81c784; height: 40px; border-radius: 4px;"></div>
<div style="background: #4caf50; height: 40px; border-radius: 4px;"></div>
<div style="background: #a5d6a7; height: 40px; border-radius: 4px;"></div>
<div style="background: #e8f5e9; height: 40px; border-radius: 4px;"></div>
<div style="background: #e8f5e9; height: 40px; border-radius: 4px;"></div>
<div>Afternoon</div>
<div style="background: #4caf50; height: 40px; border-radius: 4px;"></div>
<div style="background: #2e7d32; height: 40px; border-radius: 4px;"></div>
<div style="background: #4caf50; height: 40px; border-radius: 4px;"></div>
<div style="background: #81c784; height: 40px; border-radius: 4px;"></div>
<div style="background: #4caf50; height: 40px; border-radius: 4px;"></div>
<div style="background: #a5d6a7; height: 40px; border-radius: 4px;"></div>
<div style="background: #c8e6c9; height: 40px; border-radius: 4px;"></div>
<div>Evening</div>
<div style="background: #81c784; height: 40px; border-radius: 4px;"></div>
<div style="background: #a5d6a7; height: 40px; border-radius: 4px;"></div>
<div style="background: #c8e6c9; height: 40px; border-radius: 4px;"></div>
<div style="background: #e8f5e9; height: 40px; border-radius: 4px;"></div>
<div style="background: #e8f5e9; height: 40px; border-radius: 4px;"></div>
<div style="background: #81c784; height: 40px; border-radius: 4px;"></div>
<div style="background: #4caf50; height: 40px; border-radius: 4px;"></div>
</div>
<div style="margin-top: 15px; text-align: center; color: #666;">
<span style="display: inline-block; width: 12px; height: 12px; background: #e8f5e9; margin-right: 5px;"></span> Low
<span style="display: inline-block; width: 12px; height: 12px; background: #81c784; margin: 0 5px 0 20px;"></span> Medium
<span style="display: inline-block; width: 12px; height: 12px; background: #4caf50; margin: 0 5px 0 20px;"></span> High
<span style="display: inline-block; width: 12px; height: 12px; background: #2e7d32; margin: 0 5px 0 20px;"></span> Very High
</div>
</div>
</div>
`,
buttons: [
{
label: 'Export Report',
icon: 'download',
onClick: async () => {
await PluginAPI.showSnack({
msg: 'Generating productivity report...',
type: 'INFO',
ico: 'download',
});
},
},
{
label: 'Share',
icon: 'share',
onClick: async () => {
await PluginAPI.showSnack({
msg: 'Sharing options would appear here',
type: 'INFO',
ico: 'share',
});
},
},
{
label: 'Close',
icon: 'close',
color: 'primary',
},
],
});
log('Analytics dialog opened', 'success');
}
// Initial message
log(
'API Test Plugin Dashboard loaded. Click buttons to test individual APIs or run all tests.',
'info',
);
</script>
</body>
</html>