Add documentation infrastructure and certificate pinning

- Add mdBook configuration (book.toml) for documentation
- Create new docs style guide appendix for conversation examples
- Add WhatsApp-style chat CSS for consistent doc formatting
- Replace flow diagram references with screen mockup SVGs
- Create comprehensive SVG interface mockups for all Suite apps:
  - Main suite layout and individual app screens
  - Analytics, Calendar, Chat, Compliance, Designer
  - Drive, Mail, Meet, Paper, Player, Research
  - Sources, Tasks interfaces
- Implement certificate pinning module (cert_pinning.rs) with:
  - SPKI fingerprint validation using SHA-256
  - Support for primary and backup pins
  - Pin rotation with expiration tracking
  - Report-only mode for testing
  - Validation caching for performance
- Add ring crate dependency for cryptographic operations
This commit is contained in:
Rodrigo Rodriguez (Pragmatismo) 2025-12-01 16:15:52 -03:00
parent 55d092472b
commit e7fe4e5526
50 changed files with 6490 additions and 255 deletions

1
Cargo.lock generated
View file

@ -1465,6 +1465,7 @@ dependencies = [
"regex",
"reqwest 0.12.24",
"rhai",
"ring 0.17.14",
"rust_xlsxwriter",
"rustls 0.21.12",
"rustls-native-certs 0.6.3",

View file

@ -151,6 +151,7 @@ rcgen = { version = "0.11", features = ["pem"] }
x509-parser = "0.15"
rustls-native-certs = "0.6"
webpki-roots = "0.25"
ring = "0.17"
time = { version = "0.3", features = ["formatting", "parsing"] }
jsonwebtoken = "9.3"
tower-cookies = "0.10"

19
docs/book.toml Normal file
View file

@ -0,0 +1,19 @@
[book]
title = "General Bots Documentation"
authors = ["General Bots Team"]
language = "en"
multilingual = false
src = "src"
[build]
build-dir = "book"
[output.html]
default-theme = "light"
preferred-dark-theme = "navy"
smart-punctuation = true
additional-css = ["src/custom.css", "src/whatsapp-chat.css"]
additional-js = ["src/theme-sync.js"]
[output.html.favicon]
png = "favicon.png"

View file

@ -317,5 +317,7 @@
- [Appendix C: Environment Variables](./appendix-env-vars/README.md)
- [Appendix D: Documentation Style](./appendix-docs-style/conversation-examples.md)
[Glossary](./glossary.md)
[Contact](./contact/README.md)

View file

@ -0,0 +1,235 @@
# Conversation Examples Style Guide
> **Standard format for displaying bot-user conversations in documentation**
## Overview
All conversation examples in General Bots documentation use a WhatsApp-style chat format. This provides a consistent, familiar, and readable way to show bot interactions.
## CSS Include
The styling is defined in `/assets/wa-chat.css`. Include it in your mdBook or HTML output.
---
## Basic Structure
```html
<div class="wa-chat">
<div class="wa-message bot">
<div class="wa-bubble">
<p>Bot message here</p>
<div class="wa-time">10:30</div>
</div>
</div>
<div class="wa-message user">
<div class="wa-bubble">
<p>User message here</p>
<div class="wa-time">10:31</div>
</div>
</div>
</div>
```
---
## Message Types
### Bot Message
```html
<div class="wa-message bot">
<div class="wa-bubble">
<p>Hello! How can I help you today?</p>
<div class="wa-time">10:30</div>
</div>
</div>
```
### User Message
```html
<div class="wa-message user">
<div class="wa-bubble">
<p>What meetings do I have today?</p>
<div class="wa-time">10:31</div>
</div>
</div>
```
---
## Formatting Within Messages
### Multiple Paragraphs
```html
<div class="wa-bubble">
<p>You have 2 meetings scheduled:</p>
<p>• 2:00 PM - Team Standup (30 min)</p>
<p>• 4:00 PM - Project Review (1 hour)</p>
<div class="wa-time">10:31</div>
</div>
```
### Bold Text
```html
<p><strong>Name:</strong> John Smith</p>
<p><strong>Email:</strong> john@example.com</p>
```
### Emoji Usage
Emojis are encouraged to make conversations more expressive:
| Purpose | Emoji Examples |
|---------|----------------|
| Success | ✅ ✓ 🎉 |
| Warning | ⚠️ ⚡ |
| Error | ❌ 🔴 |
| Info | 📋 |
| File | 📄 📁 📎 |
| Calendar | 📅 🗓️ |
| Email | 📧 ✉️ |
| Person | 👤 👥 |
| Time | 🕐 ⏱️ |
### File Attachments
```html
<div class="wa-message user">
<div class="wa-bubble">
<p>Here's the report</p>
<p>📎 quarterly-report.pdf</p>
<div class="wa-time">10:32</div>
</div>
</div>
```
### Action Buttons (visual representation)
```html
<p>[📧 Send] [✏️ Edit] [🗑 Discard]</p>
```
---
## Complete Example
```html
<div class="wa-chat">
<div class="wa-message user">
<div class="wa-bubble">
<p>Schedule a meeting with Sarah tomorrow at 2pm</p>
<div class="wa-time">10:30</div>
</div>
</div>
<div class="wa-message bot">
<div class="wa-bubble">
<p>✅ Meeting scheduled!</p>
<p>👥 Meeting with Sarah</p>
<p>📅 Tomorrow at 2:00 PM</p>
<p>⏱️ Duration: 1 hour</p>
<p>Invitation sent to Sarah.</p>
<div class="wa-time">10:30</div>
</div>
</div>
</div>
```
**Rendered Output:**
<div class="wa-chat">
<div class="wa-message user">
<div class="wa-bubble">
<p>Schedule a meeting with Sarah tomorrow at 2pm</p>
<div class="wa-time">10:30</div>
</div>
</div>
<div class="wa-message bot">
<div class="wa-bubble">
<p>✅ Meeting scheduled!</p>
<p>👥 Meeting with Sarah</p>
<p>📅 Tomorrow at 2:00 PM</p>
<p>⏱️ Duration: 1 hour</p>
<p>Invitation sent to Sarah.</p>
<div class="wa-time">10:30</div>
</div>
</div>
</div>
---
## Variants
### Full Width
Add `wa-full-width` class for wider conversations:
```html
<div class="wa-chat wa-full-width">
...
</div>
```
### Compact
Add `wa-compact` class for tighter spacing:
```html
<div class="wa-chat wa-compact">
...
</div>
```
### Hide Timestamps
Add `wa-no-time` class to hide timestamps:
```html
<div class="wa-chat wa-no-time">
...
</div>
```
---
## Best Practices
1. **Keep messages concise** - Break long bot responses into multiple paragraphs
2. **Use consistent timestamps** - Use realistic times (10:30, 10:31, etc.)
3. **Start with user context** - Show what the user asked before the bot response
4. **Include visual feedback** - Use emojis for status (✅, ❌, 📋)
5. **Show realistic flows** - Include multi-turn conversations when appropriate
6. **Use semantic formatting** - Bold for labels, lists for options
---
## Files Using This Format
This format is used throughout the documentation:
- `chapter-02/template-crm-contacts.md`
- `chapter-04-gbui/apps/*.md`
- `chapter-06-gbdialog/basic-vs-automation-tools.md`
- And many more...
---
## See Also
- [UI Structure](../chapter-04-gbui/ui-structure.md)
- [Chat App Documentation](../chapter-04-gbui/apps/chat.md)
<style>
.wa-chat{background-color:#e5ddd5;border-radius:8px;padding:20px 15px;margin:20px 0;max-width:500px;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;font-size:14px}
.wa-message{margin-bottom:10px}
.wa-message.user{text-align:right}
.wa-message.user .wa-bubble{background-color:#dcf8c6;display:inline-block;text-align:left}
.wa-message.bot .wa-bubble{background-color:#fff;display:inline-block}
.wa-bubble{padding:8px 12px;border-radius:8px;box-shadow:0 1px .5px rgba(0,0,0,.13);max-width:85%}
.wa-bubble p{margin:0 0 4px 0;line-height:1.4;color:#303030}
.wa-bubble p:last-child{margin-bottom:0}
.wa-time{font-size:11px;color:#8696a0;text-align:right;margin-top:4px}
</style>

View file

@ -0,0 +1,195 @@
<svg width="900" height="550" xmlns="http://www.w3.org/2000/svg">
<style>
.bg { fill: #f5f5f5; }
.frame { fill: none; stroke: #333; stroke-width: 2; }
.panel-bg { fill: #fafafa; }
.header-bg { fill: #e8e8e8; }
.main-text { fill: #1a1a1a; font-family: Arial, sans-serif; }
.secondary-text { fill: #666; font-family: Arial, sans-serif; }
.icon-text { fill: #333; font-family: Arial, sans-serif; }
.divider { stroke: #ddd; stroke-width: 1; }
.button { fill: #4A90E2; }
.button-text { fill: #fff; font-family: Arial, sans-serif; }
.input-field { fill: #fff; stroke: #ccc; stroke-width: 1; }
.card { fill: #fff; stroke: #ddd; stroke-width: 1; }
.metric-value { fill: #1a1a1a; font-family: Arial, sans-serif; font-weight: bold; }
.metric-label { fill: #666; font-family: Arial, sans-serif; }
.metric-change-up { fill: #7ED321; font-family: Arial, sans-serif; }
.metric-change-down { fill: #E74C3C; font-family: Arial, sans-serif; }
.chart-line { stroke: #4A90E2; stroke-width: 2; fill: none; }
.chart-area { fill: #4A90E2; opacity: 0.1; }
.chart-grid { stroke: #eee; stroke-width: 1; }
.bar { fill: #4A90E2; }
.bar-alt { fill: #BD10E0; }
.dropdown { fill: #fff; stroke: #ccc; stroke-width: 1; }
@media (prefers-color-scheme: dark) {
.bg { fill: #1a1a1a; }
.frame { stroke: #555; }
.panel-bg { fill: #222; }
.header-bg { fill: #2a2a2a; }
.main-text { fill: #ffffff; }
.secondary-text { fill: #aaa; }
.icon-text { fill: #ddd; }
.divider { stroke: #444; }
.input-field { fill: #2a2a2a; stroke: #444; }
.card { fill: #2a2a2a; stroke: #444; }
.metric-value { fill: #ffffff; }
.metric-label { fill: #aaa; }
.chart-grid { stroke: #333; }
.dropdown { fill: #2a2a2a; stroke: #444; }
.button { fill: #00D4FF; }
.chart-line { stroke: #00D4FF; }
.bar { fill: #00D4FF; }
.bar-alt { fill: #E040FB; }
.chart-area { fill: #00D4FF; opacity: 0.1; }
}
</style>
<!-- Title -->
<text x="450" y="30" text-anchor="middle" font-size="20" font-weight="600" class="main-text">Analytics - Dashboard Interface</text>
<!-- Main Frame -->
<rect x="30" y="50" width="840" height="470" rx="8" class="frame bg"/>
<!-- Header -->
<rect x="30" y="50" width="840" height="50" rx="8" class="header-bg"/>
<rect x="30" y="92" width="840" height="8" class="bg"/>
<!-- Title and Controls -->
<text x="55" y="82" font-size="16" font-weight="600" class="main-text">📊 Analytics Dashboard</text>
<!-- Time Range Dropdown -->
<g transform="translate(550, 62)">
<rect x="0" y="0" width="120" height="30" rx="4" class="dropdown"/>
<text x="15" y="20" font-size="13" class="main-text">Last 24h ▼</text>
</g>
<!-- Refresh Button -->
<g transform="translate(680, 62)">
<rect x="0" y="0" width="80" height="30" rx="4" class="button"/>
<text x="40" y="20" text-anchor="middle" font-size="13" class="button-text">⟳ Refresh</text>
</g>
<!-- Divider -->
<line x1="30" y1="100" x2="870" y2="100" class="divider"/>
<!-- Metric Cards Row -->
<g transform="translate(50, 115)">
<!-- Card 1: Messages -->
<rect x="0" y="0" width="185" height="90" rx="8" class="card"/>
<text x="92" y="35" text-anchor="middle" font-size="28" class="metric-value">1,234</text>
<text x="92" y="55" text-anchor="middle" font-size="13" class="metric-label">Messages</text>
<text x="92" y="75" text-anchor="middle" font-size="12" class="metric-change-up">↑ +12%</text>
<!-- Card 2: Success Rate -->
<rect x="200" y="0" width="185" height="90" rx="8" class="card"/>
<text x="292" y="35" text-anchor="middle" font-size="28" class="metric-value">89%</text>
<text x="292" y="55" text-anchor="middle" font-size="13" class="metric-label">Success Rate</text>
<text x="292" y="75" text-anchor="middle" font-size="12" class="metric-change-up">↑ +3%</text>
<!-- Card 3: Avg Response Time -->
<rect x="400" y="0" width="185" height="90" rx="8" class="card"/>
<text x="492" y="35" text-anchor="middle" font-size="28" class="metric-value">2.3s</text>
<text x="492" y="55" text-anchor="middle" font-size="13" class="metric-label">Avg Response</text>
<text x="492" y="75" text-anchor="middle" font-size="12" class="metric-change-down">↓ -0.2s</text>
<!-- Card 4: Users Today -->
<rect x="600" y="0" width="185" height="90" rx="8" class="card"/>
<text x="692" y="35" text-anchor="middle" font-size="28" class="metric-value">45</text>
<text x="692" y="55" text-anchor="middle" font-size="13" class="metric-label">Users Today</text>
<text x="692" y="75" text-anchor="middle" font-size="12" class="metric-change-up">↑ +8</text>
</g>
<!-- Charts Row -->
<g transform="translate(50, 220)">
<!-- Line Chart: Messages Over Time -->
<rect x="0" y="0" width="480" height="200" rx="8" class="card"/>
<text x="20" y="25" font-size="14" font-weight="500" class="main-text">Messages Over Time</text>
<!-- Chart Grid -->
<g transform="translate(30, 45)">
<line x1="0" y1="0" x2="430" y2="0" class="chart-grid"/>
<line x1="0" y1="40" x2="430" y2="40" class="chart-grid"/>
<line x1="0" y1="80" x2="430" y2="80" class="chart-grid"/>
<line x1="0" y1="120" x2="430" y2="120" class="chart-grid"/>
<!-- Chart Area -->
<path d="M0,100 Q50,80 100,60 T200,40 T300,50 T400,20 L400,120 L0,120 Z" class="chart-area"/>
<!-- Chart Line -->
<path d="M0,100 Q50,80 100,60 T200,40 T300,50 T400,20" class="chart-line"/>
<!-- Data Points -->
<circle cx="0" cy="100" r="4" class="bar"/>
<circle cx="100" cy="60" r="4" class="bar"/>
<circle cx="200" cy="40" r="4" class="bar"/>
<circle cx="300" cy="50" r="4" class="bar"/>
<circle cx="400" cy="20" r="4" class="bar"/>
<!-- X-axis Labels -->
<text x="0" y="140" text-anchor="middle" font-size="10" class="secondary-text">Mon</text>
<text x="100" y="140" text-anchor="middle" font-size="10" class="secondary-text">Tue</text>
<text x="200" y="140" text-anchor="middle" font-size="10" class="secondary-text">Wed</text>
<text x="300" y="140" text-anchor="middle" font-size="10" class="secondary-text">Thu</text>
<text x="400" y="140" text-anchor="middle" font-size="10" class="secondary-text">Fri</text>
</g>
<!-- Bar Chart: Top Questions -->
<rect x="500" y="0" width="285" height="200" rx="8" class="card"/>
<text x="520" y="25" font-size="14" font-weight="500" class="main-text">Top Questions</text>
<g transform="translate(520, 45)">
<!-- Bar 1 -->
<text x="0" y="12" font-size="11" class="secondary-text">1. How do I reset...</text>
<rect x="0" y="18" width="200" height="16" rx="3" class="bar"/>
<!-- Bar 2 -->
<text x="0" y="52" font-size="11" class="secondary-text">2. What is the status...</text>
<rect x="0" y="58" width="160" height="16" rx="3" class="bar"/>
<!-- Bar 3 -->
<text x="0" y="92" font-size="11" class="secondary-text">3. Where can I find...</text>
<rect x="0" y="98" width="130" height="16" rx="3" class="bar"/>
<!-- Bar 4 -->
<text x="0" y="132" font-size="11" class="secondary-text">4. Help with login</text>
<rect x="0" y="138" width="100" height="16" rx="3" class="bar"/>
</g>
</g>
<!-- Quick Stats Row -->
<g transform="translate(50, 435)">
<rect x="0" y="0" width="785" height="45" rx="6" class="card"/>
<text x="20" y="28" font-size="12" class="secondary-text">📈 Peak Hour:</text>
<text x="100" y="28" font-size="12" font-weight="500" class="main-text">2:00 PM</text>
<line x1="160" y1="10" x2="160" y2="35" class="divider"/>
<text x="180" y="28" font-size="12" class="secondary-text">🔝 Top Intent:</text>
<text x="260" y="28" font-size="12" font-weight="500" class="main-text">Support Query</text>
<line x1="370" y1="10" x2="370" y2="35" class="divider"/>
<text x="390" y="28" font-size="12" class="secondary-text">⚡ Avg Session:</text>
<text x="480" y="28" font-size="12" font-weight="500" class="main-text">4.2 min</text>
<line x1="540" y1="10" x2="540" y2="35" class="divider"/>
<text x="560" y="28" font-size="12" class="secondary-text">🎯 Resolution:</text>
<text x="640" y="28" font-size="12" font-weight="500" class="main-text">94%</text>
<!-- Export Button -->
<rect x="700" y="8" width="70" height="28" rx="4" class="button"/>
<text x="735" y="27" text-anchor="middle" font-size="11" class="button-text">Export</text>
</g>
<!-- Legend -->
<g transform="translate(30, 535)">
<text x="0" y="0" font-size="11" class="secondary-text">Metrics: Real-time KPIs</text>
<text x="150" y="0" font-size="11" class="secondary-text">Charts: Trends & Distribution</text>
<text x="350" y="0" font-size="11" class="secondary-text">Time Range: Last 24h, 7d, 30d, Custom</text>
<text x="600" y="0" font-size="11" class="secondary-text">Shortcuts: R = Refresh | E = Export</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.9 KiB

View file

@ -0,0 +1,211 @@
<svg width="900" height="550" xmlns="http://www.w3.org/2000/svg">
<style>
.bg { fill: #f5f5f5; }
.frame { fill: none; stroke: #333; stroke-width: 2; }
.header-bg { fill: #e8e8e8; }
.main-text { fill: #1a1a1a; font-family: Arial, sans-serif; }
.secondary-text { fill: #666; font-family: Arial, sans-serif; }
.icon-text { fill: #333; font-family: Arial, sans-serif; }
.divider { stroke: #ddd; stroke-width: 1; }
.button { fill: #4A90E2; }
.button-text { fill: #fff; font-family: Arial, sans-serif; }
.input-field { fill: #fff; stroke: #ccc; stroke-width: 1; }
.today { fill: #4A90E2; }
.event-bg { fill: #4A90E2; opacity: 0.8; }
.event-text { fill: #fff; font-family: Arial, sans-serif; }
.weekend { fill: #f0f0f0; }
.cell-border { stroke: #e0e0e0; stroke-width: 1; fill: none; }
.nav-btn { fill: #f0f0f0; stroke: #ccc; stroke-width: 1; }
.view-active { fill: #4A90E2; }
.view-inactive { fill: #e0e0e0; }
@media (prefers-color-scheme: dark) {
.bg { fill: #1a1a1a; }
.frame { stroke: #555; }
.header-bg { fill: #2a2a2a; }
.main-text { fill: #ffffff; }
.secondary-text { fill: #aaa; }
.icon-text { fill: #ddd; }
.divider { stroke: #444; }
.input-field { fill: #2a2a2a; stroke: #444; }
.today { fill: #00D4FF; }
.event-bg { fill: #00D4FF; opacity: 0.8; }
.weekend { fill: #252525; }
.cell-border { stroke: #444; }
.nav-btn { fill: #333; stroke: #555; }
.button { fill: #00D4FF; }
.view-active { fill: #00D4FF; }
.view-inactive { fill: #333; }
}
</style>
<!-- Title -->
<text x="450" y="30" text-anchor="middle" font-size="20" font-weight="600" class="main-text">Calendar - Scheduling Interface</text>
<!-- Main Frame -->
<rect x="30" y="50" width="840" height="470" rx="8" class="frame bg"/>
<!-- Header -->
<rect x="30" y="50" width="840" height="50" rx="8" class="header-bg"/>
<rect x="30" y="92" width="840" height="8" class="bg"/>
<!-- Navigation -->
<g transform="translate(50, 62)">
<!-- Prev/Next Buttons -->
<rect x="0" y="0" width="30" height="30" rx="4" class="nav-btn"/>
<text x="15" y="21" text-anchor="middle" font-size="16" class="icon-text"></text>
<rect x="40" y="0" width="30" height="30" rx="4" class="nav-btn"/>
<text x="55" y="21" text-anchor="middle" font-size="16" class="icon-text"></text>
<!-- Month/Year -->
<text x="100" y="22" font-size="18" font-weight="600" class="main-text">March 2024</text>
</g>
<!-- View Toggle -->
<g transform="translate(650, 62)">
<rect x="0" y="0" width="50" height="30" rx="4" class="view-inactive"/>
<text x="25" y="20" text-anchor="middle" font-size="12" class="main-text">Day</text>
<rect x="55" y="0" width="55" height="30" rx="4" class="view-inactive"/>
<text x="82" y="20" text-anchor="middle" font-size="12" class="main-text">Week</text>
<rect x="115" y="0" width="60" height="30" rx="4" class="view-active"/>
<text x="145" y="20" text-anchor="middle" font-size="12" fill="#fff">Month</text>
</g>
<!-- Divider -->
<line x1="30" y1="100" x2="870" y2="100" class="divider"/>
<!-- Calendar Grid -->
<g transform="translate(50, 110)">
<!-- Day Headers -->
<g>
<text x="55" y="20" text-anchor="middle" font-size="13" font-weight="500" class="secondary-text">Mon</text>
<text x="170" y="20" text-anchor="middle" font-size="13" font-weight="500" class="secondary-text">Tue</text>
<text x="285" y="20" text-anchor="middle" font-size="13" font-weight="500" class="secondary-text">Wed</text>
<text x="400" y="20" text-anchor="middle" font-size="13" font-weight="500" class="secondary-text">Thu</text>
<text x="515" y="20" text-anchor="middle" font-size="13" font-weight="500" class="secondary-text">Fri</text>
<text x="630" y="20" text-anchor="middle" font-size="13" font-weight="500" class="secondary-text">Sat</text>
<text x="745" y="20" text-anchor="middle" font-size="13" font-weight="500" class="secondary-text">Sun</text>
</g>
<!-- Grid Lines and Cells -->
<!-- Row 1 -->
<g transform="translate(0, 35)">
<rect x="0" y="0" width="115" height="65" class="cell-border"/>
<rect x="115" y="0" width="115" height="65" class="cell-border"/>
<rect x="230" y="0" width="115" height="65" class="cell-border"/>
<rect x="345" y="0" width="115" height="65" class="cell-border"/>
<text x="435" y="20" text-anchor="middle" font-size="14" class="main-text">1</text>
<rect x="460" y="0" width="115" height="65" class="cell-border"/>
<text x="550" y="20" text-anchor="middle" font-size="14" class="main-text">2</text>
<rect x="575" y="0" width="115" height="65" class="cell-border weekend"/>
<text x="665" y="20" text-anchor="middle" font-size="14" class="secondary-text">3</text>
<rect x="690" y="0" width="110" height="65" class="cell-border weekend"/>
</g>
<!-- Row 2 -->
<g transform="translate(0, 100)">
<rect x="0" y="0" width="115" height="65" class="cell-border"/>
<text x="15" y="20" font-size="14" class="main-text">4</text>
<rect x="115" y="0" width="115" height="65" class="cell-border"/>
<text x="130" y="20" font-size="14" class="main-text">5</text>
<!-- Event -->
<rect x="120" y="28" width="105" height="22" rx="3" class="event-bg"/>
<text x="125" y="43" font-size="11" class="event-text">Team Meeting</text>
<rect x="230" y="0" width="115" height="65" class="cell-border"/>
<text x="245" y="20" font-size="14" class="main-text">6</text>
<rect x="345" y="0" width="115" height="65" class="cell-border"/>
<text x="360" y="20" font-size="14" class="main-text">7</text>
<rect x="460" y="0" width="115" height="65" class="cell-border"/>
<text x="475" y="20" font-size="14" class="main-text">8</text>
<rect x="575" y="0" width="115" height="65" class="cell-border weekend"/>
<text x="590" y="20" font-size="14" class="secondary-text">9</text>
<rect x="690" y="0" width="110" height="65" class="cell-border weekend"/>
<text x="705" y="20" font-size="14" class="secondary-text">10</text>
</g>
<!-- Row 3 -->
<g transform="translate(0, 165)">
<rect x="0" y="0" width="115" height="65" class="cell-border"/>
<text x="15" y="20" font-size="14" class="main-text">11</text>
<rect x="115" y="0" width="115" height="65" class="cell-border"/>
<text x="130" y="20" font-size="14" class="main-text">12</text>
<rect x="230" y="0" width="115" height="65" class="cell-border"/>
<text x="245" y="20" font-size="14" class="main-text">13</text>
<!-- Event -->
<rect x="235" y="28" width="105" height="22" rx="3" class="event-bg"/>
<text x="240" y="43" font-size="11" class="event-text">Project Review</text>
<rect x="345" y="0" width="115" height="65" class="cell-border"/>
<text x="360" y="20" font-size="14" class="main-text">14</text>
<!-- Event -->
<rect x="350" y="28" width="105" height="22" rx="3" class="event-bg"/>
<text x="355" y="43" font-size="11" class="event-text">1:1 Meeting</text>
<rect x="460" y="0" width="115" height="65" class="cell-border"/>
<!-- Today -->
<circle cx="485" cy="18" r="14" class="today"/>
<text x="485" y="23" text-anchor="middle" font-size="14" fill="#fff">15</text>
<rect x="575" y="0" width="115" height="65" class="cell-border weekend"/>
<text x="590" y="20" font-size="14" class="secondary-text">16</text>
<rect x="690" y="0" width="110" height="65" class="cell-border weekend"/>
<text x="705" y="20" font-size="14" class="secondary-text">17</text>
</g>
<!-- Row 4 -->
<g transform="translate(0, 230)">
<rect x="0" y="0" width="115" height="65" class="cell-border"/>
<text x="15" y="20" font-size="14" class="main-text">18</text>
<rect x="115" y="0" width="115" height="65" class="cell-border"/>
<text x="130" y="20" font-size="14" class="main-text">19</text>
<rect x="230" y="0" width="115" height="65" class="cell-border"/>
<text x="245" y="20" font-size="14" class="main-text">20</text>
<rect x="345" y="0" width="115" height="65" class="cell-border"/>
<text x="360" y="20" font-size="14" class="main-text">21</text>
<rect x="460" y="0" width="115" height="65" class="cell-border"/>
<text x="475" y="20" font-size="14" class="main-text">22</text>
<rect x="575" y="0" width="115" height="65" class="cell-border weekend"/>
<text x="590" y="20" font-size="14" class="secondary-text">23</text>
<rect x="690" y="0" width="110" height="65" class="cell-border weekend"/>
<text x="705" y="20" font-size="14" class="secondary-text">24</text>
</g>
</g>
<!-- Add Event Button -->
<g transform="translate(750, 470)">
<circle cx="30" cy="30" r="28" class="button"/>
<text x="30" y="38" text-anchor="middle" font-size="28" fill="#fff">+</text>
</g>
<!-- Legend -->
<g transform="translate(30, 535)">
<circle cx="10" cy="-4" r="8" class="today"/>
<text x="25" y="0" font-size="11" class="secondary-text">Today</text>
<rect x="80" y="-10" width="40" height="14" rx="3" class="event-bg"/>
<text x="130" y="0" font-size="11" class="secondary-text">Event</text>
<rect x="200" y="-10" width="20" height="14" class="weekend"/>
<text x="230" y="0" font-size="11" class="secondary-text">Weekend</text>
<text x="400" y="0" font-size="11" class="secondary-text">Shortcuts: N = New event | T = Today | ← → = Navigate | D/W/M = View</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.5 KiB

View file

@ -0,0 +1,200 @@
<svg width="900" height="550" xmlns="http://www.w3.org/2000/svg">
<style>
.bg { fill: #f5f5f5; }
.frame { fill: none; stroke: #333; stroke-width: 2; }
.panel-bg { fill: #fafafa; }
.header-bg { fill: #e8e8e8; }
.main-text { fill: #1a1a1a; font-family: Arial, sans-serif; }
.secondary-text { fill: #666; font-family: Arial, sans-serif; }
.icon-text { fill: #333; font-family: Arial, sans-serif; }
.divider { stroke: #ddd; stroke-width: 1; }
.button { fill: #4A90E2; }
.button-text { fill: #fff; font-family: Arial, sans-serif; }
.button-secondary { fill: #fff; stroke: #ccc; stroke-width: 1; }
.input-field { fill: #fff; stroke: #ccc; stroke-width: 1; }
.card { fill: #fff; stroke: #ddd; stroke-width: 1; }
.severity-critical { fill: #E74C3C; }
.severity-high { fill: #F5A623; }
.severity-medium { fill: #F1C40F; }
.severity-low { fill: #7ED321; }
.severity-info { fill: #4A90E2; }
.severity-text { fill: #fff; font-family: Arial, sans-serif; }
.row-bg { fill: #fff; }
.row-hover { fill: #fef6f6; }
.fix-btn { fill: #E74C3C; }
.review-btn { fill: #F5A623; }
.table-header { fill: #f5f5f5; }
@media (prefers-color-scheme: dark) {
.bg { fill: #1a1a1a; }
.frame { stroke: #555; }
.panel-bg { fill: #222; }
.header-bg { fill: #2a2a2a; }
.main-text { fill: #ffffff; }
.secondary-text { fill: #aaa; }
.icon-text { fill: #ddd; }
.divider { stroke: #444; }
.input-field { fill: #2a2a2a; stroke: #444; }
.card { fill: #2a2a2a; stroke: #444; }
.row-bg { fill: #2a2a2a; }
.row-hover { fill: #3a2a2a; }
.table-header { fill: #333; }
.button { fill: #00D4FF; }
.button-secondary { fill: #333; stroke: #555; }
}
</style>
<!-- Title -->
<text x="450" y="30" text-anchor="middle" font-size="20" font-weight="600" class="main-text">Compliance - Security Scanner Interface</text>
<!-- Main Frame -->
<rect x="30" y="50" width="840" height="470" rx="8" class="frame bg"/>
<!-- Header -->
<rect x="30" y="50" width="840" height="50" rx="8" class="header-bg"/>
<rect x="30" y="92" width="840" height="8" class="bg"/>
<!-- Title and Controls -->
<text x="55" y="82" font-size="16" font-weight="600" class="main-text">🛡 Compliance Scanner</text>
<!-- Action Buttons -->
<g transform="translate(600, 60)">
<rect x="0" y="0" width="80" height="32" rx="4" class="button"/>
<text x="40" y="21" text-anchor="middle" font-size="13" class="button-text">Scan</text>
<rect x="90" y="0" width="80" height="32" rx="4" class="button-secondary"/>
<text x="130" y="21" text-anchor="middle" font-size="13" class="main-text">Export</text>
</g>
<!-- Divider -->
<line x1="30" y1="100" x2="870" y2="100" class="divider"/>
<!-- Severity Summary Cards -->
<g transform="translate(50, 115)">
<!-- Critical -->
<rect x="0" y="0" width="145" height="70" rx="8" class="card"/>
<rect x="10" y="15" width="50" height="40" rx="6" class="severity-critical"/>
<text x="35" y="42" text-anchor="middle" font-size="20" font-weight="bold" class="severity-text">2</text>
<text x="75" y="35" font-size="12" font-weight="500" class="main-text">Critical</text>
<text x="75" y="52" font-size="11" class="secondary-text">🔴 Immediate</text>
<!-- High -->
<rect x="160" y="0" width="145" height="70" rx="8" class="card"/>
<rect x="170" y="15" width="50" height="40" rx="6" class="severity-high"/>
<text x="195" y="42" text-anchor="middle" font-size="20" font-weight="bold" class="severity-text">5</text>
<text x="235" y="35" font-size="12" font-weight="500" class="main-text">High</text>
<text x="235" y="52" font-size="11" class="secondary-text">🟠 Priority</text>
<!-- Medium -->
<rect x="320" y="0" width="145" height="70" rx="8" class="card"/>
<rect x="330" y="15" width="50" height="40" rx="6" class="severity-medium"/>
<text x="355" y="42" text-anchor="middle" font-size="20" font-weight="bold" class="severity-text">3</text>
<text x="395" y="35" font-size="12" font-weight="500" class="main-text">Medium</text>
<text x="395" y="52" font-size="11" class="secondary-text">🟡 Review</text>
<!-- Low -->
<rect x="480" y="0" width="145" height="70" rx="8" class="card"/>
<rect x="490" y="15" width="50" height="40" rx="6" class="severity-low"/>
<text x="515" y="42" text-anchor="middle" font-size="20" font-weight="bold" class="severity-text">1</text>
<text x="555" y="35" font-size="12" font-weight="500" class="main-text">Low</text>
<text x="555" y="52" font-size="11" class="secondary-text">🟢 Minor</text>
<!-- Info -->
<rect x="640" y="0" width="145" height="70" rx="8" class="card"/>
<rect x="650" y="15" width="50" height="40" rx="6" class="severity-info"/>
<text x="675" y="42" text-anchor="middle" font-size="20" font-weight="bold" class="severity-text">0</text>
<text x="715" y="35" font-size="12" font-weight="500" class="main-text">Info</text>
<text x="715" y="52" font-size="11" class="secondary-text"> Notes</text>
</g>
<!-- Divider -->
<line x1="50" y1="200" x2="850" y2="200" class="divider"/>
<!-- Issues Table -->
<g transform="translate(50, 210)">
<!-- Table Header -->
<rect x="0" y="0" width="800" height="35" rx="4" class="table-header"/>
<text x="20" y="23" font-size="12" font-weight="500" class="secondary-text">Severity</text>
<text x="120" y="23" font-size="12" font-weight="500" class="secondary-text">Issue</text>
<text x="450" y="23" font-size="12" font-weight="500" class="secondary-text">File</text>
<text x="650" y="23" font-size="12" font-weight="500" class="secondary-text">Action</text>
<!-- Row 1 - Critical -->
<rect x="0" y="40" width="800" height="45" rx="4" class="row-hover"/>
<rect x="15" y="52" width="70" height="22" rx="4" class="severity-critical"/>
<text x="50" y="68" text-anchor="middle" font-size="11" class="severity-text">Critical</text>
<text x="120" y="68" font-size="13" class="main-text">Hardcoded password detected</text>
<text x="450" y="68" font-size="12" font-family="monospace" class="secondary-text">start.bas:15</text>
<rect x="650" y="52" width="55" height="24" rx="4" class="fix-btn"/>
<text x="677" y="69" text-anchor="middle" font-size="11" class="severity-text">Fix</text>
<!-- Row 2 - Critical -->
<rect x="0" y="90" width="800" height="45" rx="4" class="row-hover"/>
<rect x="15" y="102" width="70" height="22" rx="4" class="severity-critical"/>
<text x="50" y="118" text-anchor="middle" font-size="11" class="severity-text">Critical</text>
<text x="120" y="118" font-size="13" class="main-text">API key exposed in code</text>
<text x="450" y="118" font-size="12" font-family="monospace" class="secondary-text">api.bas:42</text>
<rect x="650" y="102" width="55" height="24" rx="4" class="fix-btn"/>
<text x="677" y="119" text-anchor="middle" font-size="11" class="severity-text">Fix</text>
<!-- Row 3 - High -->
<rect x="0" y="140" width="800" height="45" rx="4" class="row-bg"/>
<rect x="15" y="152" width="70" height="22" rx="4" class="severity-high"/>
<text x="50" y="168" text-anchor="middle" font-size="11" class="severity-text">High</text>
<text x="120" y="168" font-size="13" class="main-text">SQL injection risk in query</text>
<text x="450" y="168" font-size="12" font-family="monospace" class="secondary-text">data.bas:28</text>
<rect x="650" y="152" width="65" height="24" rx="4" class="review-btn"/>
<text x="682" y="169" text-anchor="middle" font-size="11" class="severity-text">Review</text>
<!-- Row 4 - High -->
<rect x="0" y="190" width="800" height="45" rx="4" class="row-bg"/>
<rect x="15" y="202" width="70" height="22" rx="4" class="severity-high"/>
<text x="50" y="218" text-anchor="middle" font-size="11" class="severity-text">High</text>
<text x="120" y="218" font-size="13" class="main-text">Insecure HTTP endpoint</text>
<text x="450" y="218" font-size="12" font-family="monospace" class="secondary-text">config.csv:8</text>
<rect x="650" y="202" width="65" height="24" rx="4" class="review-btn"/>
<text x="682" y="219" text-anchor="middle" font-size="11" class="severity-text">Review</text>
<!-- Row 5 - Medium -->
<rect x="0" y="240" width="800" height="45" rx="4" class="row-bg"/>
<rect x="15" y="252" width="70" height="22" rx="4" class="severity-medium"/>
<text x="50" y="268" text-anchor="middle" font-size="11" class="severity-text">Medium</text>
<text x="120" y="268" font-size="13" class="main-text">Missing input validation</text>
<text x="450" y="268" font-size="12" font-family="monospace" class="secondary-text">form.bas:55</text>
<rect x="650" y="252" width="65" height="24" rx="4" class="button-secondary"/>
<text x="682" y="269" text-anchor="middle" font-size="11" class="main-text">Review</text>
</g>
<!-- Footer Stats -->
<g transform="translate(50, 480)">
<text x="0" y="0" font-size="12" class="secondary-text">Last scan: 2 minutes ago</text>
<text x="200" y="0" font-size="12" class="secondary-text">Files scanned: 24</text>
<text x="380" y="0" font-size="12" class="secondary-text">Total issues: 11</text>
<!-- Pagination -->
<text x="600" y="0" font-size="12" class="secondary-text">Showing 1-5 of 11</text>
<rect x="720" y="-15" width="25" height="22" rx="4" class="button-secondary"/>
<text x="732" y="2" text-anchor="middle" font-size="12" class="main-text"></text>
<rect x="750" y="-15" width="25" height="22" rx="4" class="button-secondary"/>
<text x="762" y="2" text-anchor="middle" font-size="12" class="main-text"></text>
</g>
<!-- Legend -->
<g transform="translate(30, 535)">
<rect x="0" y="-10" width="14" height="14" rx="3" class="severity-critical"/>
<text x="20" y="0" font-size="11" class="secondary-text">Critical</text>
<rect x="70" y="-10" width="14" height="14" rx="3" class="severity-high"/>
<text x="90" y="0" font-size="11" class="secondary-text">High</text>
<rect x="130" y="-10" width="14" height="14" rx="3" class="severity-medium"/>
<text x="150" y="0" font-size="11" class="secondary-text">Medium</text>
<rect x="200" y="-10" width="14" height="14" rx="3" class="severity-low"/>
<text x="220" y="0" font-size="11" class="secondary-text">Low</text>
<text x="300" y="0" font-size="11" class="secondary-text">Fix = Auto-remediate | Review = Manual inspection needed</text>
<text x="650" y="0" font-size="11" class="secondary-text">LGPD • GDPR • CCPA</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

View file

@ -0,0 +1,258 @@
<svg width="900" height="550" xmlns="http://www.w3.org/2000/svg">
<style>
.bg { fill: #f5f5f5; }
.frame { fill: none; stroke: #333; stroke-width: 2; }
.panel-bg { fill: #fafafa; }
.header-bg { fill: #e8e8e8; }
.main-text { fill: #1a1a1a; font-family: Arial, sans-serif; }
.secondary-text { fill: #666; font-family: Arial, sans-serif; }
.icon-text { fill: #333; font-family: Arial, sans-serif; }
.divider { stroke: #ddd; stroke-width: 1; }
.button { fill: #4A90E2; }
.button-text { fill: #fff; font-family: Arial, sans-serif; }
.input-field { fill: #fff; stroke: #ccc; stroke-width: 1; }
.canvas-bg { fill: #fff; }
.canvas-grid { stroke: #f0f0f0; stroke-width: 1; }
.node-talk { fill: #4A90E2; stroke: #3a7bc8; stroke-width: 2; }
.node-hear { fill: #7ED321; stroke: #6bc01a; stroke-width: 2; }
.node-if { fill: #F5A623; stroke: #d9911f; stroke-width: 2; }
.node-text { fill: #fff; font-family: Arial, sans-serif; }
.connector { stroke: #666; stroke-width: 2; fill: none; }
.connector-arrow { fill: #666; }
.toolbox-item { fill: #fff; stroke: #ddd; stroke-width: 1; }
.toolbox-item:hover { fill: #f0f7ff; }
.properties-panel { fill: #fafafa; }
.section-header { fill: #e8e8e8; }
@media (prefers-color-scheme: dark) {
.bg { fill: #1a1a1a; }
.frame { stroke: #555; }
.panel-bg { fill: #222; }
.header-bg { fill: #2a2a2a; }
.main-text { fill: #ffffff; }
.secondary-text { fill: #aaa; }
.icon-text { fill: #ddd; }
.divider { stroke: #444; }
.input-field { fill: #2a2a2a; stroke: #444; }
.canvas-bg { fill: #252525; }
.canvas-grid { stroke: #333; }
.toolbox-item { fill: #2a2a2a; stroke: #444; }
.properties-panel { fill: #222; }
.section-header { fill: #333; }
.connector { stroke: #888; }
.connector-arrow { fill: #888; }
.button { fill: #00D4FF; }
.node-talk { fill: #00D4FF; stroke: #00a8cc; }
.node-hear { fill: #00FF88; stroke: #00cc6d; }
.node-if { fill: #FF9500; stroke: #cc7700; }
}
</style>
<defs>
<marker id="arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" class="connector-arrow"/>
</marker>
</defs>
<!-- Title -->
<text x="450" y="30" text-anchor="middle" font-size="20" font-weight="600" class="main-text">Designer - Visual Builder Interface</text>
<!-- Main Frame -->
<rect x="30" y="50" width="840" height="470" rx="8" class="frame bg"/>
<!-- Left Panel - Toolbox -->
<rect x="30" y="50" width="120" height="470" rx="8" class="panel-bg"/>
<line x1="150" y1="50" x2="150" y2="520" class="divider"/>
<!-- Toolbox Header -->
<rect x="30" y="50" width="120" height="30" rx="8" class="section-header"/>
<rect x="30" y="72" width="120" height="8" class="panel-bg"/>
<text x="90" y="70" text-anchor="middle" font-size="12" font-weight="500" class="main-text">Toolbox</text>
<!-- Toolbox Items -->
<g transform="translate(40, 90)">
<!-- TALK -->
<rect x="0" y="0" width="100" height="35" rx="4" class="toolbox-item"/>
<text x="15" y="23" font-size="14" class="icon-text">💬</text>
<text x="35" y="23" font-size="12" class="main-text">TALK</text>
<!-- HEAR -->
<rect x="0" y="45" width="100" height="35" rx="4" class="toolbox-item"/>
<text x="15" y="68" font-size="14" class="icon-text">👂</text>
<text x="35" y="68" font-size="12" class="main-text">HEAR</text>
<!-- SET -->
<rect x="0" y="90" width="100" height="35" rx="4" class="toolbox-item"/>
<text x="15" y="113" font-size="14" class="icon-text">📝</text>
<text x="35" y="113" font-size="12" class="main-text">SET</text>
<!-- Separator -->
<line x1="0" y1="140" x2="100" y2="140" class="divider"/>
<!-- IF -->
<rect x="0" y="155" width="100" height="35" rx="4" class="toolbox-item"/>
<text x="15" y="178" font-size="14" class="icon-text">🔀</text>
<text x="35" y="178" font-size="12" class="main-text">IF</text>
<!-- FOR -->
<rect x="0" y="200" width="100" height="35" rx="4" class="toolbox-item"/>
<text x="15" y="223" font-size="14" class="icon-text">🔄</text>
<text x="35" y="223" font-size="12" class="main-text">FOR</text>
<!-- SWITCH -->
<rect x="0" y="245" width="100" height="35" rx="4" class="toolbox-item"/>
<text x="15" y="268" font-size="14" class="icon-text">🔃</text>
<text x="35" y="268" font-size="12" class="main-text">SWITCH</text>
<!-- Separator -->
<line x1="0" y1="295" x2="100" y2="295" class="divider"/>
<!-- CALL -->
<rect x="0" y="310" width="100" height="35" rx="4" class="toolbox-item"/>
<text x="15" y="333" font-size="14" class="icon-text">📞</text>
<text x="35" y="333" font-size="12" class="main-text">CALL</text>
<!-- SEND -->
<rect x="0" y="355" width="100" height="35" rx="4" class="toolbox-item"/>
<text x="15" y="378" font-size="14" class="icon-text">📧</text>
<text x="35" y="378" font-size="12" class="main-text">SEND</text>
<!-- SAVE -->
<rect x="0" y="400" width="100" height="35" rx="4" class="toolbox-item"/>
<text x="15" y="423" font-size="14" class="icon-text">💾</text>
<text x="35" y="423" font-size="12" class="main-text">SAVE</text>
</g>
<!-- Center Panel - Canvas -->
<rect x="150" y="50" width="560" height="470" class="canvas-bg"/>
<!-- Canvas Grid (subtle) -->
<g transform="translate(150, 50)">
<line x1="0" y1="100" x2="560" y2="100" class="canvas-grid"/>
<line x1="0" y1="200" x2="560" y2="200" class="canvas-grid"/>
<line x1="0" y1="300" x2="560" y2="300" class="canvas-grid"/>
<line x1="0" y1="400" x2="560" y2="400" class="canvas-grid"/>
<line x1="100" y1="0" x2="100" y2="470" class="canvas-grid"/>
<line x1="200" y1="0" x2="200" y2="470" class="canvas-grid"/>
<line x1="300" y1="0" x2="300" y2="470" class="canvas-grid"/>
<line x1="400" y1="0" x2="400" y2="470" class="canvas-grid"/>
<line x1="500" y1="0" x2="500" y2="470" class="canvas-grid"/>
</g>
<!-- Flow Diagram on Canvas -->
<g transform="translate(200, 80)">
<!-- Node 1: TALK "Hello!" -->
<rect x="0" y="0" width="120" height="60" rx="8" class="node-talk"/>
<text x="20" y="25" font-size="14" class="node-text">💬 TALK</text>
<text x="20" y="45" font-size="12" class="node-text">"Hello!"</text>
<!-- Connector 1 to 2 -->
<line x1="60" y1="60" x2="60" y2="100" class="connector" marker-end="url(#arrowhead)"/>
<!-- Node 2: HEAR name -->
<rect x="0" y="110" width="120" height="60" rx="8" class="node-hear"/>
<text x="20" y="135" font-size="14" class="node-text">👂 HEAR</text>
<text x="20" y="155" font-size="12" class="node-text">name</text>
<!-- Connector 2 to 3 -->
<line x1="120" y1="140" x2="180" y2="140" class="connector" marker-end="url(#arrowhead)"/>
<!-- Node 3: IF condition -->
<rect x="190" y="110" width="140" height="60" rx="8" class="node-if"/>
<text x="210" y="135" font-size="14" class="node-text">🔀 IF</text>
<text x="210" y="155" font-size="12" class="node-text">name = "Jo"</text>
<!-- Branch Labels -->
<text x="220" y="195" font-size="11" class="secondary-text">Yes</text>
<text x="310" y="195" font-size="11" class="secondary-text">No</text>
<!-- Connector to Yes branch -->
<path d="M220 170 L220 200 L220 230" class="connector" marker-end="url(#arrowhead)"/>
<!-- Connector to No branch -->
<path d="M310 170 L310 200 L310 230" class="connector" marker-end="url(#arrowhead)"/>
<!-- Node 4a: TALK "Hi Jo!" -->
<rect x="160" y="240" width="120" height="60" rx="8" class="node-talk"/>
<text x="180" y="265" font-size="14" class="node-text">💬 TALK</text>
<text x="180" y="285" font-size="12" class="node-text">"Hi Jo!"</text>
<!-- Node 4b: TALK "Hello!" -->
<rect x="290" y="240" width="120" height="60" rx="8" class="node-talk"/>
<text x="310" y="265" font-size="14" class="node-text">💬 TALK</text>
<text x="310" y="285" font-size="12" class="node-text">"Hello!"</text>
</g>
<!-- Right Panel - Properties -->
<rect x="710" y="50" width="160" height="470" rx="8" class="properties-panel"/>
<line x1="710" y1="50" x2="710" y2="520" class="divider"/>
<!-- Properties Header -->
<rect x="710" y="50" width="160" height="30" rx="8" class="section-header"/>
<rect x="710" y="72" width="160" height="8" class="properties-panel"/>
<text x="790" y="70" text-anchor="middle" font-size="12" font-weight="500" class="main-text">Properties</text>
<!-- Properties Content -->
<g transform="translate(720, 95)">
<text x="0" y="0" font-size="12" class="secondary-text">Node:</text>
<text x="0" y="20" font-size="14" font-weight="500" class="main-text">TALK</text>
<line x1="0" y1="35" x2="140" y2="35" class="divider"/>
<text x="0" y="55" font-size="12" class="secondary-text">Message:</text>
<rect x="0" y="65" width="140" height="60" rx="4" class="input-field"/>
<text x="10" y="85" font-size="12" class="main-text">"Hello!"</text>
<line x1="0" y1="140" x2="140" y2="140" class="divider"/>
<text x="0" y="160" font-size="12" class="secondary-text">Voice:</text>
<rect x="0" y="170" width="140" height="30" rx="4" class="input-field"/>
<text x="10" y="190" font-size="12" class="secondary-text">Default ▼</text>
<text x="0" y="220" font-size="12" class="secondary-text">Delay:</text>
<rect x="0" y="230" width="140" height="30" rx="4" class="input-field"/>
<text x="10" y="250" font-size="12" class="main-text">0ms</text>
<line x1="0" y1="275" x2="140" y2="275" class="divider"/>
<!-- Action Buttons -->
<rect x="0" y="290" width="65" height="30" rx="4" class="button"/>
<text x="32" y="310" text-anchor="middle" font-size="11" class="button-text">Apply</text>
<rect x="75" y="290" width="65" height="30" rx="4" class="input-field"/>
<text x="107" y="310" text-anchor="middle" font-size="11" class="main-text">Delete</text>
</g>
<!-- Canvas Controls (bottom) -->
<g transform="translate(160, 490)">
<rect x="0" y="0" width="30" height="25" rx="4" class="input-field"/>
<text x="15" y="17" text-anchor="middle" font-size="14" class="icon-text">+</text>
<rect x="35" y="0" width="30" height="25" rx="4" class="input-field"/>
<text x="50" y="17" text-anchor="middle" font-size="14" class="icon-text"></text>
<rect x="70" y="0" width="30" height="25" rx="4" class="input-field"/>
<text x="85" y="17" text-anchor="middle" font-size="12" class="icon-text"></text>
<text x="120" y="17" font-size="11" class="secondary-text">100%</text>
<rect x="480" y="0" width="60" height="25" rx="4" class="button"/>
<text x="510" y="17" text-anchor="middle" font-size="11" class="button-text">▶ Run</text>
</g>
<!-- Legend -->
<g transform="translate(30, 535)">
<rect x="0" y="-10" width="20" height="14" rx="3" class="node-talk"/>
<text x="28" y="0" font-size="11" class="secondary-text">Talk</text>
<rect x="60" y="-10" width="20" height="14" rx="3" class="node-hear"/>
<text x="88" y="0" font-size="11" class="secondary-text">Hear</text>
<rect x="120" y="-10" width="20" height="14" rx="3" class="node-if"/>
<text x="148" y="0" font-size="11" class="secondary-text">Condition</text>
<text x="250" y="0" font-size="11" class="secondary-text">Drag nodes from Toolbox → Canvas | Connect by dragging</text>
<text x="600" y="0" font-size="11" class="secondary-text">Shortcuts: Delete | Ctrl+D = Duplicate | Ctrl+Z = Undo</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -0,0 +1,155 @@
<svg width="900" height="550" xmlns="http://www.w3.org/2000/svg">
<style>
.bg { fill: #f5f5f5; }
.frame { fill: none; stroke: #333; stroke-width: 2; }
.panel-bg { fill: #fafafa; }
.header-bg { fill: #e8e8e8; }
.main-text { fill: #1a1a1a; font-family: Arial, sans-serif; }
.secondary-text { fill: #666; font-family: Arial, sans-serif; }
.icon-text { fill: #333; font-family: Arial, sans-serif; }
.divider { stroke: #ddd; stroke-width: 1; }
.button { fill: #4A90E2; }
.button-text { fill: #fff; font-family: Arial, sans-serif; }
.input-field { fill: #fff; stroke: #ccc; stroke-width: 1; }
.row-hover { fill: #f0f7ff; }
.folder-icon { fill: #F5A623; }
.file-icon { fill: #4A90E2; }
.image-icon { fill: #7ED321; }
.sidebar-item { fill: none; }
.sidebar-item:hover { fill: #e8e8e8; }
.label-blue { fill: #4A90E2; }
.label-green { fill: #7ED321; }
@media (prefers-color-scheme: dark) {
.bg { fill: #1a1a1a; }
.frame { stroke: #555; }
.panel-bg { fill: #222; }
.header-bg { fill: #2a2a2a; }
.main-text { fill: #ffffff; }
.secondary-text { fill: #aaa; }
.icon-text { fill: #ddd; }
.divider { stroke: #444; }
.input-field { fill: #2a2a2a; stroke: #444; }
.row-hover { fill: #2a3a4a; }
.button { fill: #00D4FF; }
}
</style>
<!-- Title -->
<text x="450" y="30" text-anchor="middle" font-size="20" font-weight="600" class="main-text">Drive - File Management Interface</text>
<!-- Main Frame -->
<rect x="30" y="50" width="840" height="470" rx="8" class="frame bg"/>
<!-- Toolbar -->
<rect x="30" y="50" width="840" height="45" rx="8" class="header-bg"/>
<rect x="30" y="87" width="840" height="8" class="bg"/>
<!-- New Button -->
<rect x="50" y="60" width="80" height="28" rx="4" class="button"/>
<text x="90" y="79" text-anchor="middle" font-size="13" class="button-text">+ New ▼</text>
<!-- Search Bar -->
<rect x="300" y="60" width="250" height="28" rx="14" class="input-field"/>
<text x="320" y="79" font-size="13" class="secondary-text">🔍 Search files...</text>
<!-- View Toggle -->
<g transform="translate(750, 60)">
<rect x="0" y="0" width="30" height="28" rx="4" class="input-field"/>
<text x="15" y="19" text-anchor="middle" font-size="14" class="icon-text"></text>
<rect x="35" y="0" width="30" height="28" rx="4" class="input-field"/>
<text x="50" y="19" text-anchor="middle" font-size="14" class="icon-text"></text>
</g>
<!-- Divider -->
<line x1="30" y1="95" x2="870" y2="95" class="divider"/>
<!-- Left Sidebar -->
<rect x="30" y="95" width="140" height="425" class="panel-bg"/>
<line x1="170" y1="95" x2="170" y2="520" class="divider"/>
<!-- Sidebar Items -->
<g transform="translate(45, 110)">
<rect x="-5" y="-5" width="120" height="28" rx="4" class="row-hover"/>
<text x="0" y="14" font-size="14" class="main-text">📁 My Drive</text>
<text x="0" y="50" font-size="14" class="secondary-text">⭐ Starred</text>
<text x="0" y="80" font-size="14" class="secondary-text">🕐 Recent</text>
<text x="0" y="110" font-size="14" class="secondary-text">🗑 Trash</text>
<line x1="-5" y1="130" x2="115" y2="130" class="divider"/>
<text x="0" y="155" font-size="12" font-weight="500" class="secondary-text">Labels</text>
<circle cx="10" cy="175" r="6" class="label-blue"/>
<text x="25" y="180" font-size="13" class="main-text">Work</text>
<circle cx="10" cy="200" r="6" class="label-green"/>
<text x="25" y="205" font-size="13" class="main-text">Personal</text>
</g>
<!-- Breadcrumb -->
<text x="190" y="120" font-size="13" class="secondary-text">📁 My Drive Projects 2024</text>
<!-- Column Headers -->
<g transform="translate(185, 140)">
<rect x="0" y="0" width="680" height="25" class="header-bg"/>
<text x="30" y="17" font-size="12" font-weight="500" class="secondary-text"></text>
<text x="60" y="17" font-size="12" font-weight="500" class="secondary-text">Name</text>
<text x="400" y="17" font-size="12" font-weight="500" class="secondary-text">Size</text>
<text x="520" y="17" font-size="12" font-weight="500" class="secondary-text">Modified</text>
</g>
<!-- File List -->
<g transform="translate(185, 170)">
<!-- Row 1 - Folder -->
<rect x="0" y="0" width="680" height="35" class="row-hover" opacity="0.5"/>
<text x="30" y="23" font-size="14" class="secondary-text"></text>
<text x="55" y="23" font-size="16" class="folder-icon">📁</text>
<text x="80" y="23" font-size="14" class="main-text">Reports</text>
<text x="400" y="23" font-size="13" class="secondary-text"></text>
<text x="520" y="23" font-size="13" class="secondary-text">Today</text>
<!-- Row 2 - Folder -->
<rect x="0" y="40" width="680" height="35" fill="none"/>
<text x="30" y="63" font-size="14" class="secondary-text"></text>
<text x="55" y="63" font-size="16" class="folder-icon">📁</text>
<text x="80" y="63" font-size="14" class="main-text">Presentations</text>
<text x="400" y="63" font-size="13" class="secondary-text"></text>
<text x="520" y="63" font-size="13" class="secondary-text">Yesterday</text>
<!-- Row 3 - Excel File -->
<rect x="0" y="80" width="680" height="35" fill="none"/>
<text x="30" y="103" font-size="14" class="secondary-text"></text>
<text x="55" y="103" font-size="16" class="file-icon">📄</text>
<text x="80" y="103" font-size="14" class="main-text">Budget.xlsx</text>
<text x="400" y="103" font-size="13" class="secondary-text">245 KB</text>
<text x="520" y="103" font-size="13" class="secondary-text">Mar 15</text>
<!-- Row 4 - Doc File -->
<rect x="0" y="120" width="680" height="35" fill="none"/>
<text x="30" y="143" font-size="14" class="secondary-text"></text>
<text x="55" y="143" font-size="16" class="file-icon">📄</text>
<text x="80" y="143" font-size="14" class="main-text">Notes.docx</text>
<text x="400" y="143" font-size="13" class="secondary-text">12 KB</text>
<text x="520" y="143" font-size="13" class="secondary-text">Mar 14</text>
<!-- Row 5 - Image File -->
<rect x="0" y="160" width="680" height="35" fill="none"/>
<text x="30" y="183" font-size="14" class="secondary-text"></text>
<text x="55" y="183" font-size="16" class="image-icon">🖼</text>
<text x="80" y="183" font-size="14" class="main-text">Logo.png</text>
<text x="400" y="183" font-size="13" class="secondary-text">89 KB</text>
<text x="520" y="183" font-size="13" class="secondary-text">Mar 10</text>
</g>
<!-- Drag & Drop Zone -->
<rect x="185" y="380" width="680" height="100" rx="8" fill="none" stroke="#4A90E2" stroke-width="2" stroke-dasharray="8,4"/>
<text x="525" y="425" text-anchor="middle" font-size="16" class="secondary-text">📤 Drag files here to upload</text>
<text x="525" y="450" text-anchor="middle" font-size="13" class="secondary-text">or click + New to create</text>
<!-- Legend -->
<g transform="translate(30, 535)">
<text x="0" y="0" font-size="11" class="secondary-text">Sidebar: Quick access, Labels</text>
<text x="200" y="0" font-size="11" class="secondary-text">Main: File browser with sort columns</text>
<text x="500" y="0" font-size="11" class="secondary-text">Actions: Upload, Create, Search, View toggle</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.3 KiB

View file

@ -0,0 +1,147 @@
<svg width="900" height="550" xmlns="http://www.w3.org/2000/svg">
<style>
.bg { fill: #f5f5f5; }
.frame { fill: none; stroke: #333; stroke-width: 2; }
.panel-bg { fill: #fafafa; }
.header-bg { fill: #e8e8e8; }
.main-text { fill: #1a1a1a; font-family: Arial, sans-serif; }
.secondary-text { fill: #666; font-family: Arial, sans-serif; }
.icon-text { fill: #333; font-family: Arial, sans-serif; }
.divider { stroke: #ddd; stroke-width: 1; }
.button { fill: #4A90E2; }
.button-text { fill: #fff; font-family: Arial, sans-serif; }
.input-field { fill: #fff; stroke: #ccc; stroke-width: 1; }
.unread-dot { fill: #4A90E2; }
.selected-row { fill: #e8f4fd; }
.row-bg { fill: #fff; }
.sidebar-active { fill: #e8f4fd; }
.badge { fill: #4A90E2; }
.action-btn { fill: #f0f0f0; stroke: #ccc; stroke-width: 1; }
@media (prefers-color-scheme: dark) {
.bg { fill: #1a1a1a; }
.frame { stroke: #555; }
.panel-bg { fill: #222; }
.header-bg { fill: #2a2a2a; }
.main-text { fill: #ffffff; }
.secondary-text { fill: #aaa; }
.icon-text { fill: #ddd; }
.divider { stroke: #444; }
.input-field { fill: #2a2a2a; stroke: #444; }
.unread-dot { fill: #00D4FF; }
.selected-row { fill: #2a3a4a; }
.row-bg { fill: #222; }
.sidebar-active { fill: #2a3a4a; }
.badge { fill: #00D4FF; }
.button { fill: #00D4FF; }
.action-btn { fill: #333; stroke: #555; }
}
</style>
<!-- Title -->
<text x="450" y="30" text-anchor="middle" font-size="20" font-weight="600" class="main-text">Mail - Email Client Interface</text>
<!-- Main Frame -->
<rect x="30" y="50" width="840" height="470" rx="8" class="frame bg"/>
<!-- Left Sidebar -->
<rect x="30" y="50" width="130" height="470" rx="8" class="panel-bg"/>
<rect x="152" y="50" width="8" height="470" class="bg"/>
<!-- Compose Button -->
<rect x="45" y="65" width="100" height="35" rx="6" class="button"/>
<text x="95" y="88" text-anchor="middle" font-size="13" class="button-text">✏ Compose</text>
<!-- Sidebar Items -->
<g transform="translate(45, 120)">
<!-- Inbox - Active -->
<rect x="-5" y="-5" width="110" height="30" rx="4" class="sidebar-active"/>
<text x="0" y="14" font-size="14" class="main-text">📥 Inbox</text>
<rect x="75" y="2" width="22" height="16" rx="8" class="badge"/>
<text x="86" y="14" text-anchor="middle" font-size="11" fill="#fff">3</text>
<text x="0" y="50" font-size="14" class="secondary-text">📤 Sent</text>
<text x="0" y="80" font-size="14" class="secondary-text">📝 Drafts</text>
<text x="0" y="110" font-size="14" class="secondary-text">🗑 Trash</text>
</g>
<!-- Middle Panel - Email List -->
<rect x="160" y="50" width="220" height="470" class="panel-bg"/>
<line x1="380" y1="50" x2="380" y2="520" class="divider"/>
<!-- List Header -->
<rect x="160" y="50" width="220" height="35" class="header-bg"/>
<text x="175" y="73" font-size="14" font-weight="500" class="main-text">Inbox</text>
<!-- Email List Items -->
<g transform="translate(160, 90)">
<!-- Email 1 - Unread, Selected -->
<rect x="0" y="0" width="220" height="70" class="selected-row"/>
<circle cx="20" cy="20" r="5" class="unread-dot"/>
<text x="35" y="20" font-size="13" font-weight="600" class="main-text">Project Update</text>
<text x="35" y="38" font-size="12" class="secondary-text">from John</text>
<text x="175" y="20" font-size="11" class="secondary-text">10:30 AM</text>
<line x1="0" y1="70" x2="220" y2="70" class="divider"/>
<!-- Email 2 - Read -->
<rect x="0" y="70" width="220" height="70" class="row-bg"/>
<circle cx="20" cy="90" r="5" fill="none" stroke="#ccc"/>
<text x="35" y="90" font-size="13" class="main-text">Meeting Notes</text>
<text x="35" y="108" font-size="12" class="secondary-text">from Sarah</text>
<text x="175" y="90" font-size="11" class="secondary-text">Yesterday</text>
<line x1="0" y1="140" x2="220" y2="140" class="divider"/>
<!-- Email 3 - Read -->
<rect x="0" y="140" width="220" height="70" class="row-bg"/>
<circle cx="20" cy="160" r="5" fill="none" stroke="#ccc"/>
<text x="35" y="160" font-size="13" class="main-text">Invoice #1234</text>
<text x="35" y="178" font-size="12" class="secondary-text">from Vendor</text>
<text x="175" y="160" font-size="11" class="secondary-text">Mar 15</text>
<line x1="0" y1="210" x2="220" y2="210" class="divider"/>
</g>
<!-- Right Panel - Email Content -->
<rect x="380" y="50" width="490" height="470" rx="8" class="bg"/>
<!-- Email Header -->
<g transform="translate(400, 70)">
<text x="0" y="0" font-size="12" class="secondary-text">From:</text>
<text x="45" y="0" font-size="12" class="main-text">john@company.com</text>
<text x="0" y="25" font-size="12" class="secondary-text">Subject:</text>
<text x="55" y="25" font-size="14" font-weight="600" class="main-text">Project Update</text>
</g>
<!-- Divider -->
<line x1="400" y1="115" x2="850" y2="115" class="divider"/>
<!-- Email Body -->
<g transform="translate(400, 135)">
<text x="0" y="0" font-size="14" class="main-text">Hi,</text>
<text x="0" y="30" font-size="14" class="main-text">Here's the latest update on our project.</text>
<text x="0" y="55" font-size="14" class="main-text">We've completed the first milestone and</text>
<text x="0" y="80" font-size="14" class="main-text">are now moving to phase two.</text>
<text x="0" y="130" font-size="14" class="main-text">Best,</text>
<text x="0" y="155" font-size="14" class="main-text">John</text>
</g>
<!-- Action Buttons -->
<g transform="translate(400, 460)">
<rect x="0" y="0" width="80" height="35" rx="6" class="button"/>
<text x="40" y="23" text-anchor="middle" font-size="13" class="button-text">Reply</text>
<rect x="90" y="0" width="90" height="35" rx="6" class="action-btn"/>
<text x="135" y="23" text-anchor="middle" font-size="13" class="main-text">Forward</text>
<rect x="190" y="0" width="80" height="35" rx="6" class="action-btn"/>
<text x="230" y="23" text-anchor="middle" font-size="13" class="main-text">Delete</text>
</g>
<!-- Legend -->
<g transform="translate(30, 535)">
<text x="0" y="0" font-size="11" class="secondary-text">Sidebar: Folders</text>
<text x="150" y="0" font-size="11" class="secondary-text">List: Email threads</text>
<text x="320" y="0" font-size="11" class="secondary-text">Content: Read and reply</text>
<text x="550" y="0" font-size="11" class="secondary-text">Shortcuts: C = Compose | R = Reply | F = Forward</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.6 KiB

View file

@ -0,0 +1,139 @@
<svg width="900" height="550" xmlns="http://www.w3.org/2000/svg">
<style>
.bg { fill: #1a1a1a; }
.frame { fill: none; stroke: #333; stroke-width: 2; }
.panel-bg { fill: #252525; }
.header-bg { fill: #2a2a2a; }
.main-text { fill: #ffffff; font-family: Arial, sans-serif; }
.secondary-text { fill: #aaa; font-family: Arial, sans-serif; }
.icon-text { fill: #ddd; font-family: Arial, sans-serif; }
.divider { stroke: #444; stroke-width: 1; }
.video-frame { fill: #333; stroke: #444; stroke-width: 2; }
.avatar-bg { fill: #4A90E2; }
.control-btn { fill: #444; stroke: #555; stroke-width: 1; }
.control-btn-active { fill: #4A90E2; }
.control-btn-danger { fill: #E74C3C; }
.control-text { fill: #fff; font-family: Arial, sans-serif; }
.timer { fill: #7ED321; font-family: monospace; }
.participant-count { fill: #4A90E2; }
.chat-icon { fill: #fff; }
@media (prefers-color-scheme: light) {
.bg { fill: #2a2a2a; }
.frame { stroke: #444; }
.panel-bg { fill: #333; }
.header-bg { fill: #3a3a3a; }
}
</style>
<!-- Title -->
<text x="450" y="30" text-anchor="middle" font-size="20" font-weight="600" class="main-text">Meet - Video Calls Interface</text>
<!-- Main Frame -->
<rect x="30" y="50" width="840" height="470" rx="8" class="frame bg"/>
<!-- Header Bar -->
<rect x="30" y="50" width="840" height="45" rx="8" class="header-bg"/>
<rect x="30" y="87" width="840" height="8" class="bg"/>
<!-- Meeting Title -->
<text x="55" y="78" font-size="16" font-weight="500" class="main-text">Meeting Room</text>
<!-- Timer -->
<text x="450" y="78" text-anchor="middle" font-size="16" class="timer">00:15:32</text>
<!-- Header Right Controls -->
<g transform="translate(720, 58)">
<!-- Participants -->
<rect x="0" y="0" width="45" height="30" rx="4" class="control-btn"/>
<text x="15" y="20" font-size="14" class="control-text">👥</text>
<text x="35" y="20" font-size="12" class="participant-count">3</text>
<!-- Chat -->
<rect x="55" y="0" width="35" height="30" rx="4" class="control-btn"/>
<text x="72" y="20" text-anchor="middle" font-size="14" class="chat-icon">💬</text>
</g>
<!-- Divider -->
<line x1="30" y1="95" x2="870" y2="95" class="divider"/>
<!-- Video Grid Area -->
<g transform="translate(50, 110)">
<!-- Main Participant 1 (You) -->
<rect x="0" y="0" width="380" height="220" rx="8" class="video-frame"/>
<circle cx="190" cy="90" r="45" class="avatar-bg"/>
<text x="190" y="100" text-anchor="middle" font-size="32" class="main-text">👤</text>
<text x="190" y="150" text-anchor="middle" font-size="16" class="main-text">You</text>
<text x="190" y="175" text-anchor="middle" font-size="13" class="secondary-text">(Camera)</text>
<!-- Name label -->
<rect x="10" y="190" width="60" height="22" rx="4" fill="#000" opacity="0.6"/>
<text x="40" y="206" text-anchor="middle" font-size="12" class="main-text">You</text>
<!-- Mute indicator -->
<circle cx="355" cy="195" r="12" fill="#E74C3C"/>
<text x="355" y="200" text-anchor="middle" font-size="10" class="main-text">🎤</text>
<!-- Main Participant 2 (John) -->
<rect x="400" y="0" width="380" height="220" rx="8" class="video-frame"/>
<circle cx="590" cy="90" r="45" class="avatar-bg"/>
<text x="590" y="100" text-anchor="middle" font-size="32" class="main-text">👤</text>
<text x="590" y="150" text-anchor="middle" font-size="16" class="main-text">John</text>
<text x="590" y="175" text-anchor="middle" font-size="13" class="secondary-text">(Camera)</text>
<!-- Name label -->
<rect x="410" y="190" width="60" height="22" rx="4" fill="#000" opacity="0.6"/>
<text x="440" y="206" text-anchor="middle" font-size="12" class="main-text">John</text>
<!-- Participant 3 (Sarah) - Smaller -->
<rect x="0" y="235" width="250" height="145" rx="8" class="video-frame"/>
<circle cx="125" cy="290" r="35" class="avatar-bg"/>
<text x="125" y="298" text-anchor="middle" font-size="26" class="main-text">👤</text>
<text x="125" y="340" text-anchor="middle" font-size="14" class="main-text">Sarah</text>
<!-- Name label -->
<rect x="10" y="355" width="55" height="20" rx="4" fill="#000" opacity="0.6"/>
<text x="37" y="369" text-anchor="middle" font-size="11" class="main-text">Sarah</text>
</g>
<!-- Control Bar -->
<rect x="30" y="470" width="840" height="50" rx="8" class="header-bg"/>
<rect x="30" y="470" width="840" height="8" class="bg"/>
<!-- Control Buttons -->
<g transform="translate(200, 480)">
<!-- Mute Button -->
<rect x="0" y="0" width="55" height="38" rx="6" class="control-btn-danger"/>
<text x="27" y="25" text-anchor="middle" font-size="18" class="control-text">🎤</text>
<!-- Video Button -->
<rect x="70" y="0" width="55" height="38" rx="6" class="control-btn-active"/>
<text x="97" y="25" text-anchor="middle" font-size="18" class="control-text">📹</text>
<!-- Share Screen Button -->
<rect x="140" y="0" width="55" height="38" rx="6" class="control-btn"/>
<text x="167" y="25" text-anchor="middle" font-size="18" class="control-text">🖥</text>
<!-- Record Button -->
<rect x="210" y="0" width="55" height="38" rx="6" class="control-btn"/>
<text x="237" y="25" text-anchor="middle" font-size="18" class="control-text">🔴</text>
<!-- Transcribe Button -->
<rect x="280" y="0" width="55" height="38" rx="6" class="control-btn"/>
<text x="307" y="25" text-anchor="middle" font-size="18" class="control-text">📝</text>
<!-- End Call Button -->
<rect x="365" y="0" width="70" height="38" rx="6" class="control-btn-danger"/>
<text x="400" y="25" text-anchor="middle" font-size="18" class="control-text">📞</text>
</g>
<!-- Legend -->
<g transform="translate(30, 535)">
<rect x="0" y="-10" width="20" height="14" rx="3" class="control-btn-active"/>
<text x="28" y="0" font-size="11" class="secondary-text">Active</text>
<rect x="80" y="-10" width="20" height="14" rx="3" class="control-btn-danger"/>
<text x="108" y="0" font-size="11" class="secondary-text">Muted/End</text>
<rect x="180" y="-10" width="20" height="14" rx="3" class="control-btn"/>
<text x="208" y="0" font-size="11" class="secondary-text">Available</text>
<text x="350" y="0" font-size="11" class="secondary-text">Shortcuts: M = Mute | V = Video | S = Share | Space = Push-to-talk</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.4 KiB

View file

@ -0,0 +1,179 @@
<svg width="900" height="550" xmlns="http://www.w3.org/2000/svg">
<style>
.bg { fill: #f5f5f5; }
.frame { fill: none; stroke: #333; stroke-width: 2; }
.panel-bg { fill: #fafafa; }
.header-bg { fill: #e8e8e8; }
.main-text { fill: #1a1a1a; font-family: Arial, sans-serif; }
.secondary-text { fill: #666; font-family: Arial, sans-serif; }
.icon-text { fill: #333; font-family: Arial, sans-serif; }
.divider { stroke: #ddd; stroke-width: 1; }
.button { fill: #4A90E2; }
.button-text { fill: #fff; font-family: Arial, sans-serif; }
.input-field { fill: #fff; stroke: #ccc; stroke-width: 1; }
.toolbar-bg { fill: #f0f0f0; }
.toolbar-btn { fill: #fff; stroke: #ccc; stroke-width: 1; }
.toolbar-btn-active { fill: #e0e0e0; stroke: #999; stroke-width: 1; }
.ai-btn { fill: #BD10E0; }
.ai-text { fill: #fff; font-family: Arial, sans-serif; }
.sidebar-item { fill: none; }
.sidebar-active { fill: #e8f4fd; }
.cursor { stroke: #4A90E2; stroke-width: 2; }
.doc-content { fill: #fff; stroke: #ddd; stroke-width: 1; }
@media (prefers-color-scheme: dark) {
.bg { fill: #1a1a1a; }
.frame { stroke: #555; }
.panel-bg { fill: #222; }
.header-bg { fill: #2a2a2a; }
.main-text { fill: #ffffff; }
.secondary-text { fill: #aaa; }
.icon-text { fill: #ddd; }
.divider { stroke: #444; }
.input-field { fill: #2a2a2a; stroke: #444; }
.toolbar-bg { fill: #333; }
.toolbar-btn { fill: #2a2a2a; stroke: #444; }
.toolbar-btn-active { fill: #444; stroke: #555; }
.sidebar-active { fill: #2a3a4a; }
.doc-content { fill: #2a2a2a; stroke: #444; }
.button { fill: #00D4FF; }
.ai-btn { fill: #E040FB; }
.cursor { stroke: #00D4FF; }
}
</style>
<!-- Title -->
<text x="450" y="30" text-anchor="middle" font-size="20" font-weight="600" class="main-text">Paper - AI Writing Interface</text>
<!-- Main Frame -->
<rect x="30" y="50" width="840" height="470" rx="8" class="frame bg"/>
<!-- Left Sidebar - Document List -->
<rect x="30" y="50" width="140" height="470" rx="8" class="panel-bg"/>
<line x1="170" y1="50" x2="170" y2="520" class="divider"/>
<!-- Sidebar Header -->
<text x="50" y="78" font-size="14" font-weight="500" class="main-text">📄 Notes</text>
<line x1="40" y1="90" x2="160" y2="90" class="divider"/>
<!-- Document List -->
<g transform="translate(40, 100)">
<!-- Active Document -->
<rect x="-5" y="0" width="125" height="30" rx="4" class="sidebar-active"/>
<text x="0" y="20" font-size="13" class="main-text">Meeting Notes</text>
<text x="0" y="50" font-size="13" class="secondary-text">Project Plan</text>
<text x="0" y="80" font-size="13" class="secondary-text">Ideas</text>
<line x1="-5" y1="100" x2="115" y2="100" class="divider"/>
<text x="0" y="125" font-size="12" font-weight="500" class="secondary-text">Quick Start</text>
<text x="0" y="150" font-size="12" class="secondary-text">📄 Blank</text>
<text x="0" y="175" font-size="12" class="secondary-text">📋 Meeting</text>
<text x="0" y="200" font-size="12" class="secondary-text">✓ To-Do</text>
<text x="0" y="225" font-size="12" class="secondary-text">🔬 Research</text>
</g>
<!-- Main Editor Area -->
<rect x="170" y="50" width="700" height="470" class="bg"/>
<!-- Toolbar -->
<rect x="170" y="50" width="700" height="45" class="toolbar-bg"/>
<line x1="170" y1="95" x2="870" y2="95" class="divider"/>
<!-- Formatting Buttons -->
<g transform="translate(185, 58)">
<!-- Bold -->
<rect x="0" y="0" width="30" height="28" rx="4" class="toolbar-btn"/>
<text x="15" y="20" text-anchor="middle" font-size="14" font-weight="bold" class="icon-text">B</text>
<!-- Italic -->
<rect x="35" y="0" width="30" height="28" rx="4" class="toolbar-btn"/>
<text x="50" y="20" text-anchor="middle" font-size="14" font-style="italic" class="icon-text">I</text>
<!-- Underline -->
<rect x="70" y="0" width="30" height="28" rx="4" class="toolbar-btn"/>
<text x="85" y="20" text-anchor="middle" font-size="14" class="icon-text" text-decoration="underline">U</text>
<!-- Separator -->
<line x1="110" y1="5" x2="110" y2="25" class="divider"/>
<!-- H1 -->
<rect x="120" y="0" width="30" height="28" rx="4" class="toolbar-btn-active"/>
<text x="135" y="20" text-anchor="middle" font-size="12" font-weight="bold" class="icon-text">H1</text>
<!-- H2 -->
<rect x="155" y="0" width="30" height="28" rx="4" class="toolbar-btn"/>
<text x="170" y="20" text-anchor="middle" font-size="12" class="icon-text">H2</text>
<!-- Separator -->
<line x1="195" y1="5" x2="195" y2="25" class="divider"/>
<!-- Bullet List -->
<rect x="205" y="0" width="30" height="28" rx="4" class="toolbar-btn"/>
<text x="220" y="20" text-anchor="middle" font-size="14" class="icon-text"></text>
<!-- Horizontal Rule -->
<rect x="240" y="0" width="30" height="28" rx="4" class="toolbar-btn"/>
<text x="255" y="20" text-anchor="middle" font-size="14" class="icon-text"></text>
<!-- Link -->
<rect x="275" y="0" width="30" height="28" rx="4" class="toolbar-btn"/>
<text x="290" y="20" text-anchor="middle" font-size="14" class="icon-text">🔗</text>
<!-- Image -->
<rect x="310" y="0" width="30" height="28" rx="4" class="toolbar-btn"/>
<text x="325" y="20" text-anchor="middle" font-size="14" class="icon-text">📷</text>
<!-- AI Button -->
<rect x="360" y="0" width="70" height="28" rx="4" class="ai-btn"/>
<text x="395" y="19" text-anchor="middle" font-size="12" class="ai-text">AI ✨</text>
</g>
<!-- Document Content Area -->
<rect x="190" y="110" width="660" height="395" rx="4" class="doc-content"/>
<!-- Document Content -->
<g transform="translate(210, 135)">
<!-- Title -->
<text x="0" y="0" font-size="24" font-weight="bold" class="main-text">Project Proposal</text>
<line x1="0" y1="10" x2="200" y2="10" stroke="#4A90E2" stroke-width="3"/>
<!-- Section -->
<text x="0" y="55" font-size="18" font-weight="600" class="main-text">Introduction</text>
<line x1="0" y1="65" x2="100" y2="65" class="divider"/>
<!-- Body text -->
<text x="0" y="95" font-size="14" class="main-text">This document outlines our proposal for</text>
<text x="0" y="118" font-size="14" class="main-text">the upcoming project. We aim to deliver</text>
<text x="0" y="141" font-size="14" class="main-text">a comprehensive solution that addresses</text>
<text x="0" y="164" font-size="14" class="main-text">all stakeholder requirements.</text>
<!-- Cursor -->
<line x1="248" y1="150" x2="248" y2="170" class="cursor"/>
<!-- More content preview -->
<text x="0" y="210" font-size="18" font-weight="600" class="secondary-text">Key Objectives</text>
<text x="0" y="240" font-size="14" class="secondary-text">• Improve efficiency by 30%</text>
<text x="0" y="263" font-size="14" class="secondary-text">• Reduce costs through automation</text>
<text x="0" y="286" font-size="14" class="secondary-text">• Enhance user experience</text>
</g>
<!-- Word Count / Status Bar -->
<g transform="translate(190, 490)">
<text x="0" y="0" font-size="11" class="secondary-text">Words: 156</text>
<text x="100" y="0" font-size="11" class="secondary-text">Characters: 892</text>
<text x="250" y="0" font-size="11" class="secondary-text">Reading time: 1 min</text>
<text x="480" y="0" font-size="11" class="secondary-text">✓ Auto-saved 2 min ago</text>
</g>
<!-- Legend -->
<g transform="translate(30, 535)">
<rect x="0" y="-10" width="20" height="14" rx="3" class="ai-btn"/>
<text x="28" y="0" font-size="11" class="secondary-text">AI Assist</text>
<text x="100" y="0" font-size="11" class="secondary-text">Shortcuts: Ctrl+B = Bold | Ctrl+I = Italic | Ctrl+S = Save | Ctrl+/ = AI</text>
<text x="550" y="0" font-size="11" class="secondary-text">Markdown supported</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.9 KiB

View file

@ -0,0 +1,168 @@
<svg width="900" height="550" xmlns="http://www.w3.org/2000/svg">
<style>
.bg { fill: #f5f5f5; }
.frame { fill: none; stroke: #333; stroke-width: 2; }
.panel-bg { fill: #fafafa; }
.header-bg { fill: #e8e8e8; }
.main-text { fill: #1a1a1a; font-family: Arial, sans-serif; }
.secondary-text { fill: #666; font-family: Arial, sans-serif; }
.icon-text { fill: #333; font-family: Arial, sans-serif; }
.divider { stroke: #ddd; stroke-width: 1; }
.button { fill: #4A90E2; }
.button-text { fill: #fff; font-family: Arial, sans-serif; }
.input-field { fill: #fff; stroke: #ccc; stroke-width: 1; }
.search-box { fill: #fff; stroke: #4A90E2; stroke-width: 2; }
.filter-active { fill: #4A90E2; }
.filter-inactive { fill: #e0e0e0; }
.result-card { fill: #fff; stroke: #ddd; stroke-width: 1; }
.source-link { fill: #4A90E2; font-family: Arial, sans-serif; }
.sidebar-item { fill: none; }
.sidebar-active { fill: #e8f4fd; }
.collection-icon { fill: #F5A623; }
.ai-highlight { fill: #f0e6ff; stroke: #BD10E0; stroke-width: 1; }
@media (prefers-color-scheme: dark) {
.bg { fill: #1a1a1a; }
.frame { stroke: #555; }
.panel-bg { fill: #222; }
.header-bg { fill: #2a2a2a; }
.main-text { fill: #ffffff; }
.secondary-text { fill: #aaa; }
.icon-text { fill: #ddd; }
.divider { stroke: #444; }
.input-field { fill: #2a2a2a; stroke: #444; }
.search-box { fill: #2a2a2a; stroke: #00D4FF; }
.filter-inactive { fill: #333; }
.result-card { fill: #2a2a2a; stroke: #444; }
.source-link { fill: #00D4FF; }
.sidebar-active { fill: #2a3a4a; }
.button { fill: #00D4FF; }
.filter-active { fill: #00D4FF; }
.ai-highlight { fill: #2a2040; stroke: #E040FB; }
}
</style>
<!-- Title -->
<text x="450" y="30" text-anchor="middle" font-size="20" font-weight="600" class="main-text">Research - AI Search Interface</text>
<!-- Main Frame -->
<rect x="30" y="50" width="840" height="470" rx="8" class="frame bg"/>
<!-- Left Sidebar -->
<rect x="30" y="50" width="140" height="470" rx="8" class="panel-bg"/>
<line x1="170" y1="50" x2="170" y2="520" class="divider"/>
<!-- Sidebar Header -->
<text x="50" y="78" font-size="14" font-weight="500" class="main-text">🔍 Research</text>
<line x1="40" y1="90" x2="160" y2="90" class="divider"/>
<!-- Focus Filters -->
<g transform="translate(40, 105)">
<text x="0" y="0" font-size="12" font-weight="500" class="secondary-text">Focus:</text>
<!-- All - Active -->
<rect x="-5" y="10" width="115" height="26" rx="4" class="sidebar-active"/>
<text x="5" y="28" font-size="13" class="main-text">🌐 All</text>
<text x="5" y="58" font-size="13" class="secondary-text">📚 Academic</text>
<text x="5" y="83" font-size="13" class="secondary-text">💻 Code</text>
<text x="5" y="108" font-size="13" class="secondary-text">🏠 Internal</text>
<line x1="-5" y1="125" x2="115" y2="125" class="divider"/>
<!-- Collections -->
<text x="0" y="145" font-size="12" font-weight="500" class="secondary-text">Collections:</text>
<text x="5" y="170" font-size="13" class="collection-icon">📁</text>
<text x="25" y="170" font-size="13" class="main-text">Project A</text>
<text x="5" y="195" font-size="13" class="collection-icon">📁</text>
<text x="25" y="195" font-size="13" class="main-text">References</text>
<line x1="-5" y1="215" x2="115" y2="215" class="divider"/>
<!-- Recent Searches -->
<text x="0" y="235" font-size="12" font-weight="500" class="secondary-text">Recent:</text>
<text x="5" y="258" font-size="12" class="secondary-text">• market size</text>
<text x="5" y="278" font-size="12" class="secondary-text">• competitors</text>
<text x="5" y="298" font-size="12" class="secondary-text">• best practices</text>
</g>
<!-- Main Content Area -->
<rect x="170" y="50" width="700" height="470" class="bg"/>
<!-- Search Box -->
<g transform="translate(190, 70)">
<rect x="0" y="0" width="640" height="50" rx="25" class="search-box"/>
<text x="25" y="32" font-size="16" class="secondary-text">What are the best practices for...</text>
<circle cx="610" cy="25" r="18" class="button"/>
<text x="610" y="31" text-anchor="middle" font-size="16" fill="#fff"></text>
</g>
<!-- AI Answer Section -->
<g transform="translate(190, 140)">
<rect x="0" y="0" width="640" height="180" rx="8" class="ai-highlight"/>
<!-- Header -->
<text x="20" y="30" font-size="16" font-weight="600" class="main-text">AI Answer:</text>
<line x1="20" y1="42" x2="100" y2="42" stroke="#BD10E0" stroke-width="2"/>
<!-- Answer Content -->
<text x="20" y="70" font-size="14" class="main-text">Based on multiple sources, here are the key best practices:</text>
<text x="20" y="100" font-size="14" class="main-text">1. Start with clear requirements and objectives</text>
<text x="20" y="122" font-size="14" class="main-text">2. Use iterative development with frequent feedback</text>
<text x="20" y="144" font-size="14" class="main-text">3. Test early and often with real users</text>
<text x="20" y="166" font-size="14" class="main-text">4. Document decisions and maintain knowledge base</text>
</g>
<!-- Sources Section -->
<g transform="translate(190, 335)">
<text x="0" y="0" font-size="14" font-weight="600" class="main-text">Sources:</text>
<!-- Source Cards -->
<rect x="0" y="15" width="200" height="70" rx="6" class="result-card"/>
<text x="10" y="35" font-size="11" class="secondary-text">[1]</text>
<text x="30" y="35" font-size="12" class="source-link">industry-guide.com</text>
<text x="10" y="55" font-size="11" class="secondary-text">Best practices for software</text>
<text x="10" y="70" font-size="11" class="secondary-text">development in 2024...</text>
<rect x="215" y="15" width="200" height="70" rx="6" class="result-card"/>
<text x="225" y="35" font-size="11" class="secondary-text">[2]</text>
<text x="245" y="35" font-size="12" class="source-link">techblog.dev</text>
<text x="225" y="55" font-size="11" class="secondary-text">Modern development</text>
<text x="225" y="70" font-size="11" class="secondary-text">methodology overview...</text>
<rect x="430" y="15" width="200" height="70" rx="6" class="result-card"/>
<text x="440" y="35" font-size="11" class="secondary-text">[3]</text>
<text x="460" y="35" font-size="12" class="source-link">your-docs/guidelines.pdf</text>
<text x="440" y="55" font-size="11" class="secondary-text">📄 Internal document</text>
<text x="440" y="70" font-size="11" class="secondary-text">Company guidelines...</text>
</g>
<!-- Action Buttons -->
<g transform="translate(190, 430)">
<rect x="0" y="0" width="100" height="32" rx="6" class="button"/>
<text x="50" y="21" text-anchor="middle" font-size="12" class="button-text">📁 Save</text>
<rect x="110" y="0" width="100" height="32" rx="6" class="input-field"/>
<text x="160" y="21" text-anchor="middle" font-size="12" class="main-text">📤 Share</text>
<rect x="220" y="0" width="120" height="32" rx="6" class="input-field"/>
<text x="280" y="21" text-anchor="middle" font-size="12" class="main-text">🔄 Deep Dive</text>
<rect x="350" y="0" width="100" height="32" rx="6" class="input-field"/>
<text x="400" y="21" text-anchor="middle" font-size="12" class="main-text">📋 Copy</text>
</g>
<!-- Legend -->
<g transform="translate(30, 535)">
<rect x="0" y="-10" width="20" height="14" rx="3" class="ai-highlight"/>
<text x="28" y="0" font-size="11" class="secondary-text">AI Summary</text>
<rect x="100" y="-10" width="20" height="14" rx="3" class="result-card"/>
<text x="128" y="0" font-size="11" class="secondary-text">Sources</text>
<text x="220" y="0" font-size="11" class="secondary-text">Focus: Web • Academic • Code • Internal docs</text>
<text x="550" y="0" font-size="11" class="secondary-text">Enter = Search | Ctrl+S = Save</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8 KiB

View file

@ -0,0 +1,206 @@
<svg width="900" height="550" xmlns="http://www.w3.org/2000/svg">
<style>
.bg { fill: #f5f5f5; }
.frame { fill: none; stroke: #333; stroke-width: 2; }
.panel-bg { fill: #fafafa; }
.header-bg { fill: #e8e8e8; }
.main-text { fill: #1a1a1a; font-family: Arial, sans-serif; }
.secondary-text { fill: #666; font-family: Arial, sans-serif; }
.icon-text { fill: #333; font-family: Arial, sans-serif; }
.divider { stroke: #ddd; stroke-width: 1; }
.button { fill: #4A90E2; }
.button-text { fill: #fff; font-family: Arial, sans-serif; }
.input-field { fill: #fff; stroke: #ccc; stroke-width: 1; }
.tab-active { fill: #4A90E2; }
.tab-inactive { fill: #e0e0e0; }
.card { fill: #fff; stroke: #ddd; stroke-width: 1; }
.card-featured { fill: #fff; stroke: #4A90E2; stroke-width: 2; }
.sidebar-active { fill: #e8f4fd; }
.category-icon { fill: #666; }
.star-icon { fill: #F5A623; }
.tag { fill: #e8f4fd; stroke: #4A90E2; stroke-width: 1; }
.tag-text { fill: #4A90E2; font-family: Arial, sans-serif; }
@media (prefers-color-scheme: dark) {
.bg { fill: #1a1a1a; }
.frame { stroke: #555; }
.panel-bg { fill: #222; }
.header-bg { fill: #2a2a2a; }
.main-text { fill: #ffffff; }
.secondary-text { fill: #aaa; }
.icon-text { fill: #ddd; }
.divider { stroke: #444; }
.input-field { fill: #2a2a2a; stroke: #444; }
.tab-inactive { fill: #333; }
.card { fill: #2a2a2a; stroke: #444; }
.card-featured { fill: #2a2a2a; stroke: #00D4FF; }
.sidebar-active { fill: #2a3a4a; }
.button { fill: #00D4FF; }
.tab-active { fill: #00D4FF; }
.tag { fill: #1a2a3a; stroke: #00D4FF; }
.tag-text { fill: #00D4FF; }
}
</style>
<!-- Title -->
<text x="450" y="30" text-anchor="middle" font-size="20" font-weight="600" class="main-text">Sources - Prompts &amp; Templates Interface</text>
<!-- Main Frame -->
<rect x="30" y="50" width="840" height="470" rx="8" class="frame bg"/>
<!-- Header -->
<rect x="30" y="50" width="840" height="50" rx="8" class="header-bg"/>
<rect x="30" y="92" width="840" height="8" class="bg"/>
<!-- Title -->
<text x="55" y="82" font-size="16" font-weight="600" class="main-text">Sources</text>
<!-- Search Bar -->
<g transform="translate(580, 60)">
<rect x="0" y="0" width="200" height="32" rx="16" class="input-field"/>
<text x="20" y="21" font-size="13" class="secondary-text">🔍 Search...</text>
</g>
<!-- Divider -->
<line x1="30" y1="100" x2="870" y2="100" class="divider"/>
<!-- Tabs -->
<g transform="translate(50, 110)">
<rect x="0" y="0" width="90" height="32" rx="4" class="tab-active"/>
<text x="45" y="21" text-anchor="middle" font-size="12" fill="#fff">Prompts</text>
<rect x="100" y="0" width="95" height="32" rx="4" class="tab-inactive"/>
<text x="147" y="21" text-anchor="middle" font-size="12" class="main-text">Templates</text>
<rect x="205" y="0" width="105" height="32" rx="4" class="tab-inactive"/>
<text x="257" y="21" text-anchor="middle" font-size="12" class="main-text">MCP Servers</text>
<rect x="320" y="0" width="95" height="32" rx="4" class="tab-inactive"/>
<text x="367" y="21" text-anchor="middle" font-size="12" class="main-text">LLM Tools</text>
<rect x="425" y="0" width="80" height="32" rx="4" class="tab-inactive"/>
<text x="465" y="21" text-anchor="middle" font-size="12" class="main-text">Models</text>
</g>
<!-- Divider -->
<line x1="50" y1="155" x2="850" y2="155" class="divider"/>
<!-- Left Sidebar - Categories -->
<rect x="30" y="155" width="130" height="365" class="panel-bg"/>
<line x1="160" y1="155" x2="160" y2="520" class="divider"/>
<!-- Categories -->
<g transform="translate(40, 170)">
<text x="0" y="0" font-size="12" font-weight="500" class="secondary-text">Categories</text>
<line x1="0" y1="10" x2="110" y2="10" class="divider"/>
<!-- Category Items -->
<rect x="-5" y="20" width="115" height="28" rx="4" class="sidebar-active"/>
<text x="5" y="39" font-size="13" class="main-text">📝 Writing</text>
<text x="5" y="70" font-size="13" class="secondary-text">📊 Analysis</text>
<text x="5" y="98" font-size="13" class="secondary-text">💼 Business</text>
<text x="5" y="126" font-size="13" class="secondary-text">💻 Code</text>
<text x="5" y="154" font-size="13" class="secondary-text">🎨 Creative</text>
<text x="5" y="182" font-size="13" class="secondary-text">🤖 Automation</text>
<text x="5" y="210" font-size="13" class="secondary-text">📞 Support</text>
</g>
<!-- Main Content Area -->
<g transform="translate(175, 170)">
<!-- Featured Section -->
<text x="0" y="0" font-size="14" font-weight="500" class="main-text">⭐ Featured</text>
<!-- Card 1: Customer Service -->
<rect x="0" y="20" width="210" height="150" rx="8" class="card-featured"/>
<text x="15" y="50" font-size="15" font-weight="500" class="main-text">Customer</text>
<text x="15" y="70" font-size="15" font-weight="500" class="main-text">Service</text>
<line x1="15" y1="80" x2="195" y2="80" class="divider"/>
<text x="15" y="100" font-size="12" class="secondary-text">Handle support</text>
<text x="15" y="118" font-size="12" class="secondary-text">inquiries with AI</text>
<text x="15" y="136" font-size="12" class="secondary-text">assistance</text>
<!-- Use Button -->
<rect x="15" y="145" width="60" height="24" rx="4" class="button"/>
<text x="45" y="162" text-anchor="middle" font-size="11" class="button-text">Use</text>
<!-- Star -->
<text x="180" y="50" font-size="14" class="star-icon"></text>
<!-- Card 2: Sales Assistant -->
<rect x="225" y="20" width="210" height="150" rx="8" class="card-featured"/>
<text x="240" y="50" font-size="15" font-weight="500" class="main-text">Sales</text>
<text x="240" y="70" font-size="15" font-weight="500" class="main-text">Assistant</text>
<line x1="240" y1="80" x2="420" y2="80" class="divider"/>
<text x="240" y="100" font-size="12" class="secondary-text">Qualify leads and</text>
<text x="240" y="118" font-size="12" class="secondary-text">schedule meetings</text>
<text x="240" y="136" font-size="12" class="secondary-text">automatically</text>
<!-- Use Button -->
<rect x="240" y="145" width="60" height="24" rx="4" class="button"/>
<text x="270" y="162" text-anchor="middle" font-size="11" class="button-text">Use</text>
<!-- Star -->
<text x="405" y="50" font-size="14" class="star-icon"></text>
<!-- Card 3: Code Helper -->
<rect x="450" y="20" width="210" height="150" rx="8" class="card"/>
<text x="465" y="50" font-size="15" font-weight="500" class="main-text">Code</text>
<text x="465" y="70" font-size="15" font-weight="500" class="main-text">Helper</text>
<line x1="465" y1="80" x2="645" y2="80" class="divider"/>
<text x="465" y="100" font-size="12" class="secondary-text">Generate and</text>
<text x="465" y="118" font-size="12" class="secondary-text">explain code</text>
<text x="465" y="136" font-size="12" class="secondary-text">snippets</text>
<!-- Use Button -->
<rect x="465" y="145" width="60" height="24" rx="4" class="button"/>
<text x="495" y="162" text-anchor="middle" font-size="11" class="button-text">Use</text>
<!-- More Templates Section -->
<text x="0" y="200" font-size="14" font-weight="500" class="main-text">All Prompts</text>
<!-- Smaller Cards Row -->
<rect x="0" y="220" width="155" height="100" rx="6" class="card"/>
<text x="15" y="245" font-size="13" font-weight="500" class="main-text">Meeting Notes</text>
<text x="15" y="265" font-size="11" class="secondary-text">Summarize meetings</text>
<rect x="15" y="280" width="50" height="22" rx="3" class="tag"/>
<text x="40" y="295" text-anchor="middle" font-size="10" class="tag-text">Writing</text>
<rect x="105" y="280" width="40" height="22" rx="4" class="button"/>
<text x="125" y="295" text-anchor="middle" font-size="10" class="button-text">Use</text>
<rect x="165" y="220" width="155" height="100" rx="6" class="card"/>
<text x="180" y="245" font-size="13" font-weight="500" class="main-text">Data Analyst</text>
<text x="180" y="265" font-size="11" class="secondary-text">Analyze datasets</text>
<rect x="180" y="280" width="55" height="22" rx="3" class="tag"/>
<text x="207" y="295" text-anchor="middle" font-size="10" class="tag-text">Analysis</text>
<rect x="270" y="280" width="40" height="22" rx="4" class="button"/>
<text x="290" y="295" text-anchor="middle" font-size="10" class="button-text">Use</text>
<rect x="330" y="220" width="155" height="100" rx="6" class="card"/>
<text x="345" y="245" font-size="13" font-weight="500" class="main-text">Email Writer</text>
<text x="345" y="265" font-size="11" class="secondary-text">Draft pro emails</text>
<rect x="345" y="280" width="55" height="22" rx="3" class="tag"/>
<text x="372" y="295" text-anchor="middle" font-size="10" class="tag-text">Business</text>
<rect x="435" y="280" width="40" height="22" rx="4" class="button"/>
<text x="455" y="295" text-anchor="middle" font-size="10" class="button-text">Use</text>
<rect x="495" y="220" width="155" height="100" rx="6" class="card"/>
<text x="510" y="245" font-size="13" font-weight="500" class="main-text">Story Writer</text>
<text x="510" y="265" font-size="11" class="secondary-text">Creative stories</text>
<rect x="510" y="280" width="55" height="22" rx="3" class="tag"/>
<text x="537" y="295" text-anchor="middle" font-size="10" class="tag-text">Creative</text>
<rect x="600" y="280" width="40" height="22" rx="4" class="button"/>
<text x="620" y="295" text-anchor="middle" font-size="10" class="button-text">Use</text>
</g>
<!-- Pagination -->
<g transform="translate(400, 500)">
<text x="0" y="0" font-size="12" class="secondary-text">Page 1 of 5</text>
<rect x="80" y="-15" width="30" height="22" rx="4" class="input-field"/>
<text x="95" y="2" text-anchor="middle" font-size="12" class="main-text"></text>
<rect x="115" y="-15" width="30" height="22" rx="4" class="input-field"/>
<text x="130" y="2" text-anchor="middle" font-size="12" class="main-text"></text>
</g>
<!-- Legend -->
<g transform="translate(30, 535)">
<text x="0" y="0" font-size="11" class="secondary-text">Tabs: Prompts, Templates, MCP Servers, LLM Tools, Models</text>
<text x="350" y="0" font-size="11" class="secondary-text">Categories filter content</text>
<text x="550" y="0" font-size="11" class="secondary-text">Click Use to apply prompt/template</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -0,0 +1,82 @@
<svg width="800" height="500" xmlns="http://www.w3.org/2000/svg">
<style>
.bg { fill: #f5f5f5; }
.frame { fill: none; stroke: #333; stroke-width: 2; }
.header-bg { fill: #e0e0e0; }
.main-text { fill: #1a1a1a; font-family: Arial, sans-serif; }
.secondary-text { fill: #666; font-family: Arial, sans-serif; }
.icon-text { fill: #333; font-family: Arial, sans-serif; }
.divider { stroke: #ccc; stroke-width: 1; }
.button { fill: #fff; stroke: #999; stroke-width: 1; rx: 4; }
.input-field { fill: #fff; stroke: #bbb; stroke-width: 1; }
.accent { fill: #4A90E2; }
@media (prefers-color-scheme: dark) {
.bg { fill: #1a1a1a; }
.frame { stroke: #555; }
.header-bg { fill: #2a2a2a; }
.main-text { fill: #ffffff; }
.secondary-text { fill: #aaa; }
.icon-text { fill: #ddd; }
.divider { stroke: #444; }
.button { fill: #333; stroke: #555; }
.input-field { fill: #2a2a2a; stroke: #444; }
.accent { fill: #00D4FF; }
}
</style>
<!-- Title -->
<text x="400" y="30" text-anchor="middle" font-size="20" font-weight="600" class="main-text">Suite - Main Layout</text>
<!-- Main Frame -->
<rect x="50" y="50" width="700" height="420" rx="8" class="frame bg"/>
<!-- Header Bar -->
<rect x="50" y="50" width="700" height="50" rx="8" class="header-bg"/>
<rect x="50" y="92" width="700" height="8" class="bg"/>
<!-- Logo/Brand -->
<circle cx="85" cy="75" r="15" class="accent"/>
<text x="85" y="80" text-anchor="middle" font-size="14" fill="#fff">🤖</text>
<text x="115" y="80" font-size="16" font-weight="600" class="main-text">General Bots</text>
<!-- Header Right Controls -->
<g transform="translate(620, 60)">
<!-- Apps Menu -->
<rect x="0" y="0" width="35" height="30" rx="4" class="button"/>
<text x="17" y="20" text-anchor="middle" font-size="12" class="icon-text">⋮⋮⋮</text>
<!-- Theme Toggle -->
<rect x="45" y="0" width="35" height="30" rx="4" class="button"/>
<text x="62" y="20" text-anchor="middle" font-size="14" class="icon-text">🌙</text>
<!-- User Avatar -->
<circle cx="110" cy="15" r="15" class="accent"/>
<text x="110" y="20" text-anchor="middle" font-size="12" fill="#fff">U</text>
</g>
<!-- Divider -->
<line x1="50" y1="100" x2="750" y2="100" class="divider"/>
<!-- Main Chat Area -->
<rect x="70" y="120" width="660" height="280" rx="6" class="input-field"/>
<!-- Chat Area Label -->
<text x="400" y="200" text-anchor="middle" font-size="24" class="secondary-text">💬</text>
<text x="400" y="240" text-anchor="middle" font-size="18" class="main-text">Chat</text>
<text x="400" y="265" text-anchor="middle" font-size="14" class="secondary-text">(Main Area)</text>
<!-- Message Input -->
<rect x="70" y="420" width="580" height="40" rx="20" class="input-field"/>
<text x="100" y="445" font-size="14" class="secondary-text">Type your message here...</text>
<!-- Send Button -->
<rect x="660" y="420" width="70" height="40" rx="20" class="accent"/>
<text x="695" y="445" text-anchor="middle" font-size="14" fill="#fff">Send</text>
<!-- Legend -->
<g transform="translate(50, 480)">
<text x="0" y="0" font-size="11" class="secondary-text">Header: Navigation, Apps Menu, Theme, Profile</text>
<text x="400" y="0" font-size="11" class="secondary-text">Main: AI Chat Interface with Message Input</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

View file

@ -0,0 +1,151 @@
<svg width="900" height="550" xmlns="http://www.w3.org/2000/svg">
<style>
.bg { fill: #f5f5f5; }
.frame { fill: none; stroke: #333; stroke-width: 2; }
.header-bg { fill: #e8e8e8; }
.main-text { fill: #1a1a1a; font-family: Arial, sans-serif; }
.secondary-text { fill: #666; font-family: Arial, sans-serif; }
.icon-text { fill: #333; font-family: Arial, sans-serif; }
.divider { stroke: #ddd; stroke-width: 1; }
.button { fill: #4A90E2; }
.button-text { fill: #fff; font-family: Arial, sans-serif; }
.input-field { fill: #fff; stroke: #ccc; stroke-width: 1; }
.tab-active { fill: #4A90E2; }
.tab-inactive { fill: #e0e0e0; }
.priority-high { fill: #E74C3C; }
.priority-medium { fill: #F5A623; }
.priority-low { fill: #7ED321; }
.checkbox { fill: #fff; stroke: #999; stroke-width: 1.5; }
.checkbox-done { fill: #7ED321; stroke: #5cb318; stroke-width: 1.5; }
.task-done { fill: #999; text-decoration: line-through; }
.row-bg { fill: #fff; }
.row-hover { fill: #f0f7ff; }
@media (prefers-color-scheme: dark) {
.bg { fill: #1a1a1a; }
.frame { stroke: #555; }
.header-bg { fill: #2a2a2a; }
.main-text { fill: #ffffff; }
.secondary-text { fill: #aaa; }
.icon-text { fill: #ddd; }
.divider { stroke: #444; }
.input-field { fill: #2a2a2a; stroke: #444; }
.tab-inactive { fill: #333; }
.checkbox { fill: #2a2a2a; stroke: #666; }
.row-bg { fill: #222; }
.row-hover { fill: #2a3a4a; }
.button { fill: #00D4FF; }
.tab-active { fill: #00D4FF; }
}
</style>
<!-- Title -->
<text x="450" y="30" text-anchor="middle" font-size="20" font-weight="600" class="main-text">Tasks - To-Do Management Interface</text>
<!-- Main Frame -->
<rect x="30" y="50" width="840" height="470" rx="8" class="frame bg"/>
<!-- Header -->
<rect x="30" y="50" width="840" height="50" rx="8" class="header-bg"/>
<rect x="30" y="92" width="840" height="8" class="bg"/>
<!-- Title and Stats -->
<text x="55" y="82" font-size="18" font-weight="600" class="main-text">✓ Tasks</text>
<g transform="translate(600, 65)">
<text x="0" y="15" font-size="12" class="secondary-text">Total: </text>
<text x="40" y="15" font-size="12" font-weight="600" class="main-text">12</text>
<text x="70" y="15" font-size="12" class="secondary-text">Active: </text>
<text x="115" y="15" font-size="12" font-weight="600" class="main-text">5</text>
<text x="140" y="15" font-size="12" class="secondary-text">Done: </text>
<text x="180" y="15" font-size="12" font-weight="600" class="main-text">7</text>
</g>
<!-- Divider -->
<line x1="30" y1="100" x2="870" y2="100" class="divider"/>
<!-- Add Task Input -->
<g transform="translate(50, 115)">
<rect x="0" y="0" width="620" height="40" rx="6" class="input-field"/>
<text x="15" y="26" font-size="14" class="secondary-text">What needs to be done?</text>
<!-- Category Dropdown -->
<rect x="640" y="0" width="100" height="40" rx="6" class="input-field"/>
<text x="655" y="26" font-size="13" class="secondary-text">Category ▼</text>
<!-- Add Button -->
<rect x="755" y="0" width="60" height="40" rx="6" class="button"/>
<text x="785" y="26" text-anchor="middle" font-size="13" class="button-text">+ Add</text>
</g>
<!-- Divider -->
<line x1="50" y1="170" x2="850" y2="170" class="divider"/>
<!-- Filter Tabs -->
<g transform="translate(50, 185)">
<rect x="0" y="0" width="90" height="32" rx="4" class="tab-active"/>
<text x="45" y="21" text-anchor="middle" font-size="13" fill="#fff">📋 All (12)</text>
<rect x="100" y="0" width="100" height="32" rx="4" class="tab-inactive"/>
<text x="150" y="21" text-anchor="middle" font-size="13" class="main-text">⏳ Active (5)</text>
<rect x="210" y="0" width="120" height="32" rx="4" class="tab-inactive"/>
<text x="270" y="21" text-anchor="middle" font-size="13" class="main-text">✓ Completed (7)</text>
<rect x="340" y="0" width="100" height="32" rx="4" class="tab-inactive"/>
<text x="390" y="21" text-anchor="middle" font-size="13" class="main-text">⚡ Priority</text>
</g>
<!-- Divider -->
<line x1="50" y1="230" x2="850" y2="230" class="divider"/>
<!-- Task List -->
<g transform="translate(50, 245)">
<!-- Task 1 - High Priority -->
<rect x="0" y="0" width="800" height="45" rx="4" class="row-hover"/>
<rect x="15" y="12" width="20" height="20" rx="4" class="checkbox"/>
<text x="50" y="28" font-size="14" class="main-text">Review quarterly report</text>
<text x="550" y="28" font-size="13" class="secondary-text">📅 Today</text>
<circle cx="780" cy="22" r="8" class="priority-high"/>
<!-- Task 2 - Medium Priority -->
<rect x="0" y="50" width="800" height="45" rx="4" class="row-bg"/>
<rect x="15" y="62" width="20" height="20" rx="4" class="checkbox"/>
<text x="50" y="78" font-size="14" class="main-text">Call client about proposal</text>
<text x="550" y="78" font-size="13" class="secondary-text">📅 Today</text>
<circle cx="780" cy="72" r="8" class="priority-medium"/>
<!-- Task 3 - Low Priority -->
<rect x="0" y="100" width="800" height="45" rx="4" class="row-bg"/>
<rect x="15" y="112" width="20" height="20" rx="4" class="checkbox"/>
<text x="50" y="128" font-size="14" class="main-text">Update project documentation</text>
<text x="550" y="128" font-size="13" class="secondary-text">📅 Tomorrow</text>
<circle cx="780" cy="122" r="8" class="priority-low"/>
<!-- Task 4 - Completed -->
<rect x="0" y="150" width="800" height="45" rx="4" class="row-bg"/>
<rect x="15" y="162" width="20" height="20" rx="4" class="checkbox-done"/>
<text x="22" y="178" font-size="12" fill="#fff"></text>
<text x="50" y="178" font-size="14" class="task-done">Send meeting notes</text>
<text x="550" y="178" font-size="13" class="secondary-text">✓ Done</text>
<!-- Task 5 - Completed -->
<rect x="0" y="200" width="800" height="45" rx="4" class="row-bg"/>
<rect x="15" y="212" width="20" height="20" rx="4" class="checkbox-done"/>
<text x="22" y="228" font-size="12" fill="#fff"></text>
<text x="50" y="228" font-size="14" class="task-done">Complete expense report</text>
<text x="550" y="228" font-size="13" class="secondary-text">✓ Done</text>
</g>
<!-- Priority Legend -->
<g transform="translate(50, 505)">
<text x="0" y="0" font-size="12" font-weight="500" class="secondary-text">Priority:</text>
<circle cx="70" cy="-4" r="6" class="priority-high"/>
<text x="82" y="0" font-size="11" class="secondary-text">High</text>
<circle cx="130" cy="-4" r="6" class="priority-medium"/>
<text x="142" y="0" font-size="11" class="secondary-text">Medium</text>
<circle cx="210" cy="-4" r="6" class="priority-low"/>
<text x="222" y="0" font-size="11" class="secondary-text">Low</text>
<text x="350" y="0" font-size="11" class="secondary-text">Shortcuts: Enter = Add | Space = Toggle | Delete = Remove</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7 KiB

View file

@ -0,0 +1,228 @@
<svg width="900" height="600" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="accentGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#3b82f6"/>
<stop offset="100%" stop-color="#60a5fa"/>
</linearGradient>
<linearGradient id="greenGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#22c55e"/>
<stop offset="100%" stop-color="#4ade80"/>
</linearGradient>
<linearGradient id="purpleGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#8b5cf6"/>
<stop offset="100%" stop-color="#a78bfa"/>
</linearGradient>
<linearGradient id="orangeGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#f97316"/>
<stop offset="100%" stop-color="#fb923c"/>
</linearGradient>
</defs>
<style>
.bg { fill: #ffffff; }
.sidebar-bg { fill: #f8fafc; }
.main-text { fill: #1e293b; font-family: system-ui, -apple-system, sans-serif; }
.secondary-text { fill: #64748b; font-family: system-ui, -apple-system, sans-serif; }
.muted-text { fill: #94a3b8; font-family: system-ui, -apple-system, sans-serif; }
.white-text { fill: #ffffff; font-family: system-ui, -apple-system, sans-serif; }
.accent-text { fill: #3b82f6; font-family: system-ui, -apple-system, sans-serif; }
.green-text { fill: #22c55e; font-family: system-ui, -apple-system, sans-serif; }
.red-text { fill: #ef4444; font-family: system-ui, -apple-system, sans-serif; }
.border { stroke: #e2e8f0; stroke-width: 1; fill: none; }
.icon-btn { fill: #f1f5f9; }
.card-bg { fill: #f8fafc; }
.chart-line { stroke: #3b82f6; stroke-width: 2; fill: none; }
.chart-area { fill: #3b82f6; opacity: 0.1; }
.grid-line { stroke: #e2e8f0; stroke-width: 1; }
.bar-blue { fill: #3b82f6; }
.bar-green { fill: #22c55e; }
.bar-purple { fill: #8b5cf6; }
@media (prefers-color-scheme: dark) {
.bg { fill: #0f172a; }
.sidebar-bg { fill: #1e293b; }
.main-text { fill: #e2e8f0; }
.secondary-text { fill: #94a3b8; }
.muted-text { fill: #64748b; }
.accent-text { fill: #60a5fa; }
.green-text { fill: #4ade80; }
.red-text { fill: #f87171; }
.border { stroke: #334155; }
.icon-btn { fill: #334155; }
.card-bg { fill: #1e293b; }
.grid-line { stroke: #334155; }
}
</style>
<text x="450" y="25" text-anchor="middle" font-size="16" font-weight="600" class="main-text">Analytics - Dashboard</text>
<rect x="30" y="40" width="840" height="530" rx="8" class="bg"/>
<rect x="30" y="40" width="840" height="530" rx="8" class="border"/>
<!-- Header -->
<g transform="translate(50, 55)">
<text x="0" y="20" font-size="20" font-weight="600" class="main-text">Dashboard Overview</text>
<text x="0" y="40" font-size="13" class="secondary-text">Last 30 days • Updated 5 min ago</text>
<!-- Date Range Selector -->
<g transform="translate(550, 5)">
<rect x="0" y="0" width="120" height="32" rx="6" class="icon-btn"/>
<rect x="0" y="0" width="120" height="32" rx="6" class="border"/>
<text x="15" y="21" font-size="12">📅</text>
<text x="35" y="21" font-size="12" class="secondary-text">Last 30 days</text>
<text x="105" y="21" font-size="10" class="muted-text"></text>
<rect x="130" y="0" width="80" height="32" rx="6" fill="url(#accentGrad)"/>
<text x="170" y="21" text-anchor="middle" font-size="12" class="white-text">Export</text>
</g>
</g>
<!-- Metric Cards Row -->
<g transform="translate(50, 105)">
<!-- Card 1: Total Users -->
<rect x="0" y="0" width="185" height="95" rx="10" class="card-bg"/>
<rect x="0" y="0" width="185" height="95" rx="10" class="border"/>
<text x="15" y="25" font-size="12" class="secondary-text">Total Users</text>
<text x="15" y="55" font-size="26" font-weight="700" class="main-text">12,847</text>
<text x="15" y="78" font-size="12" class="green-text">↑ 12.5%</text>
<text x="65" y="78" font-size="11" class="muted-text">vs last month</text>
<rect x="145" y="15" width="28" height="28" rx="8" fill="url(#accentGrad)"/>
<text x="159" y="34" text-anchor="middle" font-size="14" class="white-text">👥</text>
<!-- Card 2: Active Sessions -->
<rect x="200" y="0" width="185" height="95" rx="10" class="card-bg"/>
<rect x="200" y="0" width="185" height="95" rx="10" class="border"/>
<text x="215" y="25" font-size="12" class="secondary-text">Active Sessions</text>
<text x="215" y="55" font-size="26" font-weight="700" class="main-text">1,429</text>
<text x="215" y="78" font-size="12" class="green-text">↑ 8.2%</text>
<text x="260" y="78" font-size="11" class="muted-text">vs last month</text>
<rect x="345" y="15" width="28" height="28" rx="8" fill="url(#greenGrad)"/>
<text x="359" y="34" text-anchor="middle" font-size="14" class="white-text">📊</text>
<!-- Card 3: Avg Response Time -->
<rect x="400" y="0" width="185" height="95" rx="10" class="card-bg"/>
<rect x="400" y="0" width="185" height="95" rx="10" class="border"/>
<text x="415" y="25" font-size="12" class="secondary-text">Avg Response Time</text>
<text x="415" y="55" font-size="26" font-weight="700" class="main-text">1.2s</text>
<text x="415" y="78" font-size="12" class="green-text">↓ 15%</text>
<text x="455" y="78" font-size="11" class="muted-text">faster</text>
<rect x="545" y="15" width="28" height="28" rx="8" fill="url(#purpleGrad)"/>
<text x="559" y="34" text-anchor="middle" font-size="14" class="white-text"></text>
<!-- Card 4: Satisfaction -->
<rect x="600" y="0" width="185" height="95" rx="10" class="card-bg"/>
<rect x="600" y="0" width="185" height="95" rx="10" class="border"/>
<text x="615" y="25" font-size="12" class="secondary-text">Satisfaction Rate</text>
<text x="615" y="55" font-size="26" font-weight="700" class="main-text">94.2%</text>
<text x="615" y="78" font-size="12" class="green-text">↑ 2.1%</text>
<text x="658" y="78" font-size="11" class="muted-text">vs last month</text>
<rect x="745" y="15" width="28" height="28" rx="8" fill="url(#orangeGrad)"/>
<text x="759" y="34" text-anchor="middle" font-size="14" class="white-text"></text>
</g>
<!-- Charts Row -->
<g transform="translate(50, 220)">
<!-- Line Chart: User Activity -->
<rect x="0" y="0" width="480" height="200" rx="10" class="card-bg"/>
<rect x="0" y="0" width="480" height="200" rx="10" class="border"/>
<text x="20" y="25" font-size="14" font-weight="600" class="main-text">User Activity</text>
<text x="380" y="25" font-size="11" class="muted-text">Daily active users</text>
<!-- Grid Lines -->
<line x1="50" y1="50" x2="460" y2="50" class="grid-line"/>
<line x1="50" y1="85" x2="460" y2="85" class="grid-line"/>
<line x1="50" y1="120" x2="460" y2="120" class="grid-line"/>
<line x1="50" y1="155" x2="460" y2="155" class="grid-line"/>
<!-- Y-axis labels -->
<text x="40" y="54" text-anchor="end" font-size="10" class="muted-text">2k</text>
<text x="40" y="89" text-anchor="end" font-size="10" class="muted-text">1.5k</text>
<text x="40" y="124" text-anchor="end" font-size="10" class="muted-text">1k</text>
<text x="40" y="159" text-anchor="end" font-size="10" class="muted-text">500</text>
<!-- Line Chart Path -->
<path d="M50,130 L100,110 L150,125 L200,95 L250,80 L300,90 L350,65 L400,75 L460,55" class="chart-line"/>
<path d="M50,130 L100,110 L150,125 L200,95 L250,80 L300,90 L350,65 L400,75 L460,55 L460,155 L50,155 Z" class="chart-area"/>
<!-- Data Points -->
<circle cx="50" cy="130" r="4" fill="#3b82f6"/>
<circle cx="100" cy="110" r="4" fill="#3b82f6"/>
<circle cx="150" cy="125" r="4" fill="#3b82f6"/>
<circle cx="200" cy="95" r="4" fill="#3b82f6"/>
<circle cx="250" cy="80" r="4" fill="#3b82f6"/>
<circle cx="300" cy="90" r="4" fill="#3b82f6"/>
<circle cx="350" cy="65" r="4" fill="#3b82f6"/>
<circle cx="400" cy="75" r="4" fill="#3b82f6"/>
<circle cx="460" cy="55" r="4" fill="#3b82f6"/>
<!-- X-axis labels -->
<text x="50" y="175" text-anchor="middle" font-size="10" class="muted-text">1</text>
<text x="150" y="175" text-anchor="middle" font-size="10" class="muted-text">8</text>
<text x="250" y="175" text-anchor="middle" font-size="10" class="muted-text">15</text>
<text x="350" y="175" text-anchor="middle" font-size="10" class="muted-text">22</text>
<text x="460" y="175" text-anchor="middle" font-size="10" class="muted-text">30</text>
<text x="255" y="193" text-anchor="middle" font-size="10" class="muted-text">March 2024</text>
<!-- Bar Chart: Messages by Type -->
<rect x="500" y="0" width="285" height="200" rx="10" class="card-bg"/>
<rect x="500" y="0" width="285" height="200" rx="10" class="border"/>
<text x="520" y="25" font-size="14" font-weight="600" class="main-text">Messages by Type</text>
<!-- Bars -->
<rect x="540" y="55" width="40" height="100" rx="4" class="bar-blue"/>
<rect x="600" y="75" width="40" height="80" rx="4" class="bar-green"/>
<rect x="660" y="95" width="40" height="60" rx="4" class="bar-purple"/>
<rect x="720" y="115" width="40" height="40" rx="4" fill="#f97316"/>
<!-- Bar labels -->
<text x="560" y="170" text-anchor="middle" font-size="10" class="muted-text">Chat</text>
<text x="620" y="170" text-anchor="middle" font-size="10" class="muted-text">Email</text>
<text x="680" y="170" text-anchor="middle" font-size="10" class="muted-text">Voice</text>
<text x="740" y="170" text-anchor="middle" font-size="10" class="muted-text">Other</text>
<!-- Bar values -->
<text x="560" y="50" text-anchor="middle" font-size="11" class="main-text">4.2k</text>
<text x="620" y="70" text-anchor="middle" font-size="11" class="main-text">3.1k</text>
<text x="680" y="90" text-anchor="middle" font-size="11" class="main-text">1.8k</text>
<text x="740" y="110" text-anchor="middle" font-size="11" class="main-text">890</text>
</g>
<!-- Bottom Row -->
<g transform="translate(50, 440)">
<!-- Top Queries Table -->
<rect x="0" y="0" width="380" height="115" rx="10" class="card-bg"/>
<rect x="0" y="0" width="380" height="115" rx="10" class="border"/>
<text x="20" y="25" font-size="14" font-weight="600" class="main-text">Top Queries</text>
<text x="20" y="50" font-size="12" class="main-text">1. "How do I reset my password?"</text>
<text x="330" y="50" text-anchor="end" font-size="12" class="secondary-text">847</text>
<text x="20" y="70" font-size="12" class="main-text">2. "Billing information"</text>
<text x="330" y="70" text-anchor="end" font-size="12" class="secondary-text">623</text>
<text x="20" y="90" font-size="12" class="main-text">3. "Schedule a meeting"</text>
<text x="330" y="90" text-anchor="end" font-size="12" class="secondary-text">512</text>
<text x="330" y="108" text-anchor="end" font-size="11" class="accent-text">View all →</text>
<!-- Performance Metrics -->
<rect x="400" y="0" width="385" height="115" rx="10" class="card-bg"/>
<rect x="400" y="0" width="385" height="115" rx="10" class="border"/>
<text x="420" y="25" font-size="14" font-weight="600" class="main-text">Performance</text>
<text x="420" y="50" font-size="12" class="secondary-text">Resolution Rate</text>
<rect x="420" y="58" width="200" height="8" rx="4" fill="#e2e8f0"/>
<rect x="420" y="58" width="170" height="8" rx="4" fill="#22c55e"/>
<text x="640" y="67" font-size="12" class="main-text">85%</text>
<text x="420" y="85" font-size="12" class="secondary-text">Escalation Rate</text>
<rect x="420" y="93" width="200" height="8" rx="4" fill="#e2e8f0"/>
<rect x="420" y="93" width="30" height="8" rx="4" fill="#f97316"/>
<text x="640" y="102" font-size="12" class="main-text">15%</text>
</g>
<!-- Footer -->
<g transform="translate(50, 565)">
<text x="0" y="0" font-size="10" class="muted-text">R = Refresh | E = Export | D = Date range | F = Filter</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -0,0 +1,265 @@
<svg width="900" height="600" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="accentGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#3b82f6"/>
<stop offset="100%" stop-color="#60a5fa"/>
</linearGradient>
</defs>
<style>
.bg { fill: #ffffff; }
.sidebar-bg { fill: #f8fafc; }
.main-text { fill: #1e293b; font-family: system-ui, -apple-system, sans-serif; }
.secondary-text { fill: #64748b; font-family: system-ui, -apple-system, sans-serif; }
.muted-text { fill: #94a3b8; font-family: system-ui, -apple-system, sans-serif; }
.white-text { fill: #ffffff; font-family: system-ui, -apple-system, sans-serif; }
.accent-text { fill: #3b82f6; font-family: system-ui, -apple-system, sans-serif; }
.border { stroke: #e2e8f0; stroke-width: 1; fill: none; }
.icon-btn { fill: #f1f5f9; }
.today-circle { fill: #3b82f6; }
.event-blue { fill: #3b82f6; }
.event-green { fill: #22c55e; }
.event-purple { fill: #8b5cf6; }
.event-orange { fill: #f97316; }
.grid-line { stroke: #e2e8f0; stroke-width: 1; }
.hour-text { fill: #94a3b8; font-family: system-ui, -apple-system, sans-serif; }
@media (prefers-color-scheme: dark) {
.bg { fill: #0f172a; }
.sidebar-bg { fill: #1e293b; }
.main-text { fill: #e2e8f0; }
.secondary-text { fill: #94a3b8; }
.muted-text { fill: #64748b; }
.accent-text { fill: #60a5fa; }
.border { stroke: #334155; }
.icon-btn { fill: #334155; }
.grid-line { stroke: #334155; }
.hour-text { fill: #64748b; }
}
</style>
<text x="450" y="25" text-anchor="middle" font-size="16" font-weight="600" class="main-text">Calendar - Schedule Manager</text>
<rect x="30" y="40" width="840" height="530" rx="8" class="bg"/>
<rect x="30" y="40" width="840" height="530" rx="8" class="border"/>
<!-- Sidebar -->
<rect x="30" y="40" width="180" height="530" class="sidebar-bg"/>
<line x1="210" y1="40" x2="210" y2="570" class="border"/>
<!-- New Event Button -->
<g transform="translate(45, 55)">
<rect x="0" y="0" width="150" height="40" rx="8" fill="url(#accentGrad)"/>
<text x="75" y="26" text-anchor="middle" font-size="14" font-weight="500" class="white-text">+ New Event</text>
</g>
<!-- Mini Calendar -->
<g transform="translate(45, 115)">
<g transform="translate(0, 0)">
<text x="0" y="0" font-size="11"></text>
<text x="75" y="0" text-anchor="middle" font-size="13" font-weight="500" class="main-text">March 2024</text>
<text x="150" y="0" font-size="11"></text>
</g>
<!-- Weekday Headers -->
<g transform="translate(0, 20)">
<text x="10" y="0" text-anchor="middle" font-size="10" class="muted-text">S</text>
<text x="32" y="0" text-anchor="middle" font-size="10" class="muted-text">M</text>
<text x="54" y="0" text-anchor="middle" font-size="10" class="muted-text">T</text>
<text x="76" y="0" text-anchor="middle" font-size="10" class="muted-text">W</text>
<text x="98" y="0" text-anchor="middle" font-size="10" class="muted-text">T</text>
<text x="120" y="0" text-anchor="middle" font-size="10" class="muted-text">F</text>
<text x="142" y="0" text-anchor="middle" font-size="10" class="muted-text">S</text>
</g>
<!-- Week 1 -->
<g transform="translate(0, 38)">
<text x="10" y="0" text-anchor="middle" font-size="11" class="muted-text">25</text>
<text x="32" y="0" text-anchor="middle" font-size="11" class="muted-text">26</text>
<text x="54" y="0" text-anchor="middle" font-size="11" class="muted-text">27</text>
<text x="76" y="0" text-anchor="middle" font-size="11" class="muted-text">28</text>
<text x="98" y="0" text-anchor="middle" font-size="11" class="muted-text">29</text>
<text x="120" y="0" text-anchor="middle" font-size="11" class="main-text">1</text>
<text x="142" y="0" text-anchor="middle" font-size="11" class="main-text">2</text>
</g>
<!-- Week 2 -->
<g transform="translate(0, 56)">
<text x="10" y="0" text-anchor="middle" font-size="11" class="main-text">3</text>
<text x="32" y="0" text-anchor="middle" font-size="11" class="main-text">4</text>
<text x="54" y="0" text-anchor="middle" font-size="11" class="main-text">5</text>
<text x="76" y="0" text-anchor="middle" font-size="11" class="main-text">6</text>
<text x="98" y="0" text-anchor="middle" font-size="11" class="main-text">7</text>
<text x="120" y="0" text-anchor="middle" font-size="11" class="main-text">8</text>
<text x="142" y="0" text-anchor="middle" font-size="11" class="main-text">9</text>
</g>
<!-- Week 3 -->
<g transform="translate(0, 74)">
<text x="10" y="0" text-anchor="middle" font-size="11" class="main-text">10</text>
<text x="32" y="0" text-anchor="middle" font-size="11" class="main-text">11</text>
<text x="54" y="0" text-anchor="middle" font-size="11" class="main-text">12</text>
<text x="76" y="0" text-anchor="middle" font-size="11" class="main-text">13</text>
<text x="98" y="0" text-anchor="middle" font-size="11" class="main-text">14</text>
<circle cx="120" cy="-4" r="12" class="today-circle"/>
<text x="120" y="0" text-anchor="middle" font-size="11" class="white-text">15</text>
<text x="142" y="0" text-anchor="middle" font-size="11" class="main-text">16</text>
</g>
<!-- Week 4 -->
<g transform="translate(0, 92)">
<text x="10" y="0" text-anchor="middle" font-size="11" class="main-text">17</text>
<text x="32" y="0" text-anchor="middle" font-size="11" class="main-text">18</text>
<text x="54" y="0" text-anchor="middle" font-size="11" class="main-text">19</text>
<text x="76" y="0" text-anchor="middle" font-size="11" class="main-text">20</text>
<text x="98" y="0" text-anchor="middle" font-size="11" class="main-text">21</text>
<text x="120" y="0" text-anchor="middle" font-size="11" class="main-text">22</text>
<text x="142" y="0" text-anchor="middle" font-size="11" class="main-text">23</text>
</g>
<!-- Week 5 -->
<g transform="translate(0, 110)">
<text x="10" y="0" text-anchor="middle" font-size="11" class="main-text">24</text>
<text x="32" y="0" text-anchor="middle" font-size="11" class="main-text">25</text>
<text x="54" y="0" text-anchor="middle" font-size="11" class="main-text">26</text>
<text x="76" y="0" text-anchor="middle" font-size="11" class="main-text">27</text>
<text x="98" y="0" text-anchor="middle" font-size="11" class="main-text">28</text>
<text x="120" y="0" text-anchor="middle" font-size="11" class="main-text">29</text>
<text x="142" y="0" text-anchor="middle" font-size="11" class="main-text">30</text>
</g>
</g>
<!-- Calendars List -->
<g transform="translate(45, 270)">
<text x="0" y="0" font-size="11" font-weight="600" class="muted-text">MY CALENDARS</text>
<g transform="translate(0, 20)">
<rect x="0" y="0" width="14" height="14" rx="3" fill="#3b82f6"/>
<text x="22" y="12" font-size="13" class="main-text">Personal</text>
</g>
<g transform="translate(0, 45)">
<rect x="0" y="0" width="14" height="14" rx="3" fill="#22c55e"/>
<text x="22" y="12" font-size="13" class="main-text">Work</text>
</g>
<g transform="translate(0, 70)">
<rect x="0" y="0" width="14" height="14" rx="3" fill="#8b5cf6"/>
<text x="22" y="12" font-size="13" class="main-text">Family</text>
</g>
</g>
<!-- Main Calendar Area -->
<!-- Header -->
<g transform="translate(230, 55)">
<rect x="0" y="0" width="70" height="32" rx="6" class="icon-btn"/>
<text x="35" y="21" text-anchor="middle" font-size="12" class="secondary-text">Today</text>
<text x="90" y="21" font-size="16" class="secondary-text"></text>
<text x="115" y="21" font-size="16" class="secondary-text"></text>
<text x="150" y="22" font-size="16" font-weight="600" class="main-text">March 15, 2024</text>
<!-- View Selector -->
<g transform="translate(380, 0)">
<rect x="0" y="0" width="180" height="32" rx="6" class="icon-btn"/>
<text x="30" y="21" text-anchor="middle" font-size="12" class="muted-text">Day</text>
<rect x="55" y="4" width="50" height="24" rx="4" fill="#3b82f6"/>
<text x="80" y="21" text-anchor="middle" font-size="12" class="white-text">Week</text>
<text x="130" y="21" text-anchor="middle" font-size="12" class="muted-text">Month</text>
</g>
</g>
<!-- Week Header -->
<g transform="translate(230, 100)">
<rect x="40" y="0" width="610" height="35" class="sidebar-bg"/>
<line x1="230" y1="35" x2="850" y2="35" class="grid-line"/>
<text x="80" y="15" text-anchor="middle" font-size="11" class="secondary-text">SUN</text>
<text x="80" y="30" text-anchor="middle" font-size="14" class="secondary-text">10</text>
<text x="165" y="15" text-anchor="middle" font-size="11" class="secondary-text">MON</text>
<text x="165" y="30" text-anchor="middle" font-size="14" class="secondary-text">11</text>
<text x="250" y="15" text-anchor="middle" font-size="11" class="secondary-text">TUE</text>
<text x="250" y="30" text-anchor="middle" font-size="14" class="secondary-text">12</text>
<text x="335" y="15" text-anchor="middle" font-size="11" class="secondary-text">WED</text>
<text x="335" y="30" text-anchor="middle" font-size="14" class="secondary-text">13</text>
<text x="420" y="15" text-anchor="middle" font-size="11" class="secondary-text">THU</text>
<text x="420" y="30" text-anchor="middle" font-size="14" class="secondary-text">14</text>
<text x="505" y="15" text-anchor="middle" font-size="11" class="accent-text">FRI</text>
<circle cx="505" cy="26" r="12" class="today-circle"/>
<text x="505" y="31" text-anchor="middle" font-size="14" class="white-text">15</text>
<text x="590" y="15" text-anchor="middle" font-size="11" class="secondary-text">SAT</text>
<text x="590" y="30" text-anchor="middle" font-size="14" class="secondary-text">16</text>
</g>
<!-- Time Grid -->
<g transform="translate(230, 140)">
<!-- Time labels -->
<text x="20" y="12" text-anchor="middle" font-size="10" class="hour-text">8 AM</text>
<text x="20" y="52" text-anchor="middle" font-size="10" class="hour-text">9 AM</text>
<text x="20" y="92" text-anchor="middle" font-size="10" class="hour-text">10 AM</text>
<text x="20" y="132" text-anchor="middle" font-size="10" class="hour-text">11 AM</text>
<text x="20" y="172" text-anchor="middle" font-size="10" class="hour-text">12 PM</text>
<text x="20" y="212" text-anchor="middle" font-size="10" class="hour-text">1 PM</text>
<text x="20" y="252" text-anchor="middle" font-size="10" class="hour-text">2 PM</text>
<text x="20" y="292" text-anchor="middle" font-size="10" class="hour-text">3 PM</text>
<text x="20" y="332" text-anchor="middle" font-size="10" class="hour-text">4 PM</text>
<text x="20" y="372" text-anchor="middle" font-size="10" class="hour-text">5 PM</text>
<!-- Grid lines -->
<line x1="40" y1="5" x2="620" y2="5" class="grid-line"/>
<line x1="40" y1="45" x2="620" y2="45" class="grid-line"/>
<line x1="40" y1="85" x2="620" y2="85" class="grid-line"/>
<line x1="40" y1="125" x2="620" y2="125" class="grid-line"/>
<line x1="40" y1="165" x2="620" y2="165" class="grid-line"/>
<line x1="40" y1="205" x2="620" y2="205" class="grid-line"/>
<line x1="40" y1="245" x2="620" y2="245" class="grid-line"/>
<line x1="40" y1="285" x2="620" y2="285" class="grid-line"/>
<line x1="40" y1="325" x2="620" y2="325" class="grid-line"/>
<line x1="40" y1="365" x2="620" y2="365" class="grid-line"/>
<!-- Column dividers -->
<line x1="125" y1="0" x2="125" y2="385" class="grid-line"/>
<line x1="210" y1="0" x2="210" y2="385" class="grid-line"/>
<line x1="295" y1="0" x2="295" y2="385" class="grid-line"/>
<line x1="380" y1="0" x2="380" y2="385" class="grid-line"/>
<line x1="465" y1="0" x2="465" y2="385" class="grid-line"/>
<line x1="550" y1="0" x2="550" y2="385" class="grid-line"/>
<!-- Events -->
<!-- Monday 9-10 AM -->
<rect x="127" y="45" width="80" height="40" rx="4" class="event-green"/>
<text x="135" y="62" font-size="10" font-weight="500" class="white-text">Team Standup</text>
<text x="135" y="75" font-size="9" class="white-text">9:00 - 10:00</text>
<!-- Wednesday 11 AM - 12 PM -->
<rect x="297" y="125" width="80" height="40" rx="4" class="event-blue"/>
<text x="305" y="142" font-size="10" font-weight="500" class="white-text">Client Call</text>
<text x="305" y="155" font-size="9" class="white-text">11:00 - 12:00</text>
<!-- Friday (Today) 2-3 PM -->
<rect x="467" y="245" width="80" height="40" rx="4" class="event-purple"/>
<text x="475" y="262" font-size="10" font-weight="500" class="white-text">Project Review</text>
<text x="475" y="275" font-size="9" class="white-text">2:00 - 3:00</text>
<!-- Friday 4-5 PM -->
<rect x="467" y="325" width="80" height="40" rx="4" class="event-orange"/>
<text x="475" y="342" font-size="10" font-weight="500" class="white-text">1:1 Meeting</text>
<text x="475" y="355" font-size="9" class="white-text">4:00 - 5:00</text>
<!-- Current time indicator (Friday ~2:30 PM) -->
<line x1="465" y1="265" x2="550" y2="265" stroke="#ef4444" stroke-width="2"/>
<circle cx="465" cy="265" r="4" fill="#ef4444"/>
</g>
<!-- Footer -->
<g transform="translate(230, 555)">
<text x="0" y="0" font-size="10" class="muted-text">Click to create | Drag to reschedule | Double-click to edit</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -0,0 +1,182 @@
<svg width="900" height="600" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="accentGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#3b82f6"/>
<stop offset="100%" style="stop-color:#60a5fa"/>
</linearGradient>
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
<feDropShadow dx="0" dy="4" stdDeviation="8" flood-opacity="0.1"/>
</filter>
<filter id="shadowSm" x="-10%" y="-10%" width="120%" height="120%">
<feDropShadow dx="0" dy="2" stdDeviation="4" flood-opacity="0.08"/>
</filter>
</defs>
<style>
.bg { fill: #ffffff; }
.header-bg { fill: rgba(255,255,255,0.8); }
.main-text { fill: #1e293b; font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; }
.secondary-text { fill: #64748b; font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; }
.muted-text { fill: #94a3b8; font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; }
.accent-text { fill: #3b82f6; font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; }
.white-text { fill: #ffffff; font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; }
.card-bg { fill: #f8fafc; }
.border { stroke: #e2e8f0; stroke-width: 1; fill: none; }
.icon-btn { fill: #f1f5f9; }
.user-bubble { fill: #3b82f6; }
.bot-bubble { fill: #f8fafc; stroke: #e2e8f0; stroke-width: 1; }
.input-bg { fill: #f1f5f9; }
.suggestion { fill: #eff6ff; stroke: #3b82f6; stroke-width: 1; }
.online-dot { fill: #22c55e; }
.typing-dot { fill: #94a3b8; }
@media (prefers-color-scheme: dark) {
.bg { fill: #0f172a; }
.header-bg { fill: rgba(15,23,42,0.8); }
.main-text { fill: #e2e8f0; }
.secondary-text { fill: #94a3b8; }
.muted-text { fill: #64748b; }
.accent-text { fill: #60a5fa; }
.card-bg { fill: #1e293b; }
.border { stroke: #334155; }
.icon-btn { fill: #1e293b; }
.user-bubble { fill: #3b82f6; }
.bot-bubble { fill: #1e293b; stroke: #334155; }
.input-bg { fill: #1e293b; }
.suggestion { fill: #1e3a5f; stroke: #3b82f6; }
}
</style>
<!-- Title -->
<text x="450" y="25" text-anchor="middle" font-size="16" font-weight="600" class="main-text">Chat - AI Assistant</text>
<!-- Background -->
<rect x="30" y="40" width="840" height="530" rx="12" class="bg" filter="url(#shadow)"/>
<!-- Floating Header (Glass morphism) -->
<rect x="50" y="55" width="800" height="56" rx="12" class="header-bg" filter="url(#shadowSm)"/>
<rect x="50" y="55" width="800" height="56" rx="12" class="border"/>
<!-- Logo -->
<rect x="70" y="70" width="28" height="28" rx="8" fill="url(#accentGrad)"/>
<text x="84" y="89" text-anchor="middle" font-size="14" class="white-text">GB</text>
<text x="110" y="90" font-size="15" font-weight="600" class="main-text">General Bots</text>
<!-- Header Right: Theme, Apps Grid, Avatar -->
<g transform="translate(650, 68)">
<!-- Theme dropdown -->
<rect x="0" y="0" width="70" height="32" rx="8" class="icon-btn"/>
<text x="15" y="21" font-size="12">☀️</text>
<text x="32" y="22" font-size="12" class="secondary-text">Light</text>
<!-- Apps grid button -->
<rect x="80" y="0" width="40" height="32" rx="8" class="icon-btn"/>
<g transform="translate(91, 8)">
<circle cx="4" cy="4" r="2.5" fill="#64748b"/>
<circle cx="13" cy="4" r="2.5" fill="#64748b"/>
<circle cx="4" cy="13" r="2.5" fill="#64748b"/>
<circle cx="13" cy="13" r="2.5" fill="#64748b"/>
</g>
<!-- User avatar -->
<circle cx="155" cy="16" r="16" fill="url(#accentGrad)"/>
<text x="155" y="21" text-anchor="middle" font-size="11" font-weight="500" class="white-text">JD</text>
</g>
<!-- Chat Layout Container -->
<rect x="50" y="125" width="800" height="430" rx="0" class="bg"/>
<!-- Connection Status -->
<g transform="translate(60, 135)">
<circle cx="5" cy="5" r="4" class="online-dot"/>
</g>
<!-- Messages Area -->
<g transform="translate(80, 160)">
<!-- Bot Welcome Message -->
<g transform="translate(0, 0)">
<rect x="0" y="0" width="420" height="70" rx="16" class="bot-bubble"/>
<text x="20" y="25" font-size="12" font-weight="500" class="accent-text">AI Assistant</text>
<text x="20" y="48" font-size="14" class="main-text">Hello! I'm your AI assistant. How can I help</text>
<text x="20" y="65" font-size="14" class="main-text">you today?</text>
</g>
<!-- User Message -->
<g transform="translate(280, 90)">
<rect x="0" y="0" width="420" height="50" rx="16" class="user-bubble"/>
<text x="20" y="32" font-size="14" class="white-text">What meetings do I have scheduled for today?</text>
</g>
<!-- Bot Response with structured data -->
<g transform="translate(0, 160)">
<rect x="0" y="0" width="480" height="120" rx="16" class="bot-bubble"/>
<text x="20" y="25" font-size="12" font-weight="500" class="accent-text">AI Assistant</text>
<text x="20" y="50" font-size="14" class="main-text">You have 3 meetings scheduled for today:</text>
<text x="20" y="72" font-size="13" class="secondary-text">📅 10:00 AM - Team Standup (30 min)</text>
<text x="20" y="92" font-size="13" class="secondary-text">📅 2:00 PM - Client Call with Acme Corp (1 hr)</text>
<text x="20" y="112" font-size="13" class="secondary-text">📅 4:30 PM - 1:1 with Manager (30 min)</text>
</g>
<!-- Typing Indicator -->
<g transform="translate(0, 300)">
<rect x="0" y="0" width="80" height="40" rx="16" class="bot-bubble"/>
<circle cx="25" cy="20" r="5" class="typing-dot">
<animate attributeName="opacity" values="0.4;1;0.4" dur="1.2s" repeatCount="indefinite"/>
</circle>
<circle cx="42" cy="20" r="5" class="typing-dot">
<animate attributeName="opacity" values="0.4;1;0.4" dur="1.2s" begin="0.2s" repeatCount="indefinite"/>
</circle>
<circle cx="59" cy="20" r="5" class="typing-dot">
<animate attributeName="opacity" values="0.4;1;0.4" dur="1.2s" begin="0.4s" repeatCount="indefinite"/>
</circle>
</g>
</g>
<!-- Suggestions Container -->
<g transform="translate(80, 460)">
<rect x="0" y="0" width="130" height="36" rx="18" class="suggestion"/>
<text x="65" y="23" text-anchor="middle" font-size="12" class="accent-text">📧 Check my email</text>
<rect x="145" y="0" width="125" height="36" rx="18" class="suggestion"/>
<text x="207" y="23" text-anchor="middle" font-size="12" class="accent-text">✓ Show my tasks</text>
<rect x="285" y="0" width="140" height="36" rx="18" class="suggestion"/>
<text x="355" y="23" text-anchor="middle" font-size="12" class="accent-text">🔍 Search documents</text>
<rect x="440" y="0" width="100" height="36" rx="18" class="suggestion"/>
<text x="490" y="23" text-anchor="middle" font-size="12" class="accent-text">📝 Take notes</text>
</g>
<!-- Input Container (Footer) -->
<g transform="translate(80, 505)">
<!-- Input Field -->
<rect x="0" y="0" width="620" height="50" rx="25" class="input-bg"/>
<rect x="0" y="0" width="620" height="50" rx="25" class="border"/>
<text x="25" y="31" font-size="14" class="muted-text">Message...</text>
<!-- Voice Button -->
<g transform="translate(530, 9)">
<rect x="0" y="0" width="36" height="32" rx="16" class="icon-btn"/>
<text x="18" y="22" text-anchor="middle" font-size="16">🎤</text>
</g>
<!-- Send Button -->
<g transform="translate(640, 0)">
<rect x="0" y="0" width="60" height="50" rx="25" fill="url(#accentGrad)"/>
<text x="30" y="32" text-anchor="middle" font-size="18" class="white-text"></text>
</g>
</g>
<!-- Scroll to Bottom Button -->
<g transform="translate(800, 440)">
<circle cx="0" cy="0" r="20" class="icon-btn" filter="url(#shadowSm)"/>
<circle cx="0" cy="0" r="20" class="border"/>
<text x="0" y="6" text-anchor="middle" font-size="16" class="secondary-text"></text>
</g>
<!-- Keyboard Shortcuts Legend -->
<g transform="translate(80, 565)">
<text x="0" y="0" font-size="10" class="muted-text">💡 Tip: Use / for commands, @ to mention, # for tags</text>
<text x="450" y="0" font-size="10" class="muted-text">Enter = Send | Shift+Enter = New line | ↑ = Edit last</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.3 KiB

View file

@ -0,0 +1,279 @@
<svg width="900" height="600" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="accentGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#3b82f6"/>
<stop offset="100%" stop-color="#60a5fa"/>
</linearGradient>
<linearGradient id="greenGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#22c55e"/>
<stop offset="100%" stop-color="#4ade80"/>
</linearGradient>
<linearGradient id="redGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#ef4444"/>
<stop offset="100%" stop-color="#f87171"/>
</linearGradient>
<linearGradient id="orangeGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#f97316"/>
<stop offset="100%" stop-color="#fb923c"/>
</linearGradient>
</defs>
<style>
.bg { fill: #ffffff; }
.sidebar-bg { fill: #f8fafc; }
.main-text { fill: #1e293b; font-family: system-ui, -apple-system, sans-serif; }
.secondary-text { fill: #64748b; font-family: system-ui, -apple-system, sans-serif; }
.muted-text { fill: #94a3b8; font-family: system-ui, -apple-system, sans-serif; }
.white-text { fill: #ffffff; font-family: system-ui, -apple-system, sans-serif; }
.accent-text { fill: #3b82f6; font-family: system-ui, -apple-system, sans-serif; }
.green-text { fill: #22c55e; font-family: system-ui, -apple-system, sans-serif; }
.red-text { fill: #ef4444; font-family: system-ui, -apple-system, sans-serif; }
.orange-text { fill: #f97316; font-family: system-ui, -apple-system, sans-serif; }
.border { stroke: #e2e8f0; stroke-width: 1; fill: none; }
.icon-btn { fill: #f1f5f9; }
.card-bg { fill: #f8fafc; }
.status-pass { fill: #dcfce7; }
.status-fail { fill: #fee2e2; }
.status-warn { fill: #fef3c7; }
.progress-bg { fill: #e2e8f0; }
@media (prefers-color-scheme: dark) {
.bg { fill: #0f172a; }
.sidebar-bg { fill: #1e293b; }
.main-text { fill: #e2e8f0; }
.secondary-text { fill: #94a3b8; }
.muted-text { fill: #64748b; }
.accent-text { fill: #60a5fa; }
.green-text { fill: #4ade80; }
.red-text { fill: #f87171; }
.orange-text { fill: #fb923c; }
.border { stroke: #334155; }
.icon-btn { fill: #334155; }
.card-bg { fill: #1e293b; }
.status-pass { fill: #14532d; }
.status-fail { fill: #450a0a; }
.status-warn { fill: #451a03; }
.progress-bg { fill: #334155; }
}
</style>
<text x="450" y="25" text-anchor="middle" font-size="16" font-weight="600" class="main-text">Compliance - Security Scanner</text>
<rect x="30" y="40" width="840" height="530" rx="8" class="bg"/>
<rect x="30" y="40" width="840" height="530" rx="8" class="border"/>
<!-- Sidebar -->
<rect x="30" y="40" width="180" height="530" class="sidebar-bg"/>
<line x1="210" y1="40" x2="210" y2="570" class="border"/>
<!-- Scan Button -->
<g transform="translate(45, 55)">
<rect x="0" y="0" width="150" height="40" rx="8" fill="url(#accentGrad)"/>
<text x="75" y="26" text-anchor="middle" font-size="14" font-weight="500" class="white-text">🔍 Run Scan</text>
</g>
<!-- Navigation -->
<g transform="translate(45, 115)">
<text x="0" y="0" font-size="11" font-weight="600" class="muted-text">SCAN TYPES</text>
<g transform="translate(0, 20)">
<rect x="-10" y="-8" width="160" height="36" rx="6" fill="#eff6ff"/>
<text x="0" y="14" font-size="14">🛡️</text>
<text x="25" y="14" font-size="13" class="accent-text">All Checks</text>
</g>
<g transform="translate(0, 60)">
<text x="0" y="14" font-size="14">🔐</text>
<text x="25" y="14" font-size="13" class="secondary-text">Security</text>
</g>
<g transform="translate(0, 95)">
<text x="0" y="14" font-size="14">📋</text>
<text x="25" y="14" font-size="13" class="secondary-text">Privacy</text>
</g>
<g transform="translate(0, 130)">
<text x="0" y="14" font-size="14"></text>
<text x="25" y="14" font-size="13" class="secondary-text">Performance</text>
</g>
<g transform="translate(0, 165)">
<text x="0" y="14" font-size="14"></text>
<text x="25" y="14" font-size="13" class="secondary-text">Accessibility</text>
</g>
</g>
<!-- Compliance Frameworks -->
<g transform="translate(45, 320)">
<text x="0" y="0" font-size="11" font-weight="600" class="muted-text">FRAMEWORKS</text>
<g transform="translate(0, 20)">
<rect x="0" y="0" width="14" height="14" rx="3" fill="#22c55e"/>
<text x="22" y="12" font-size="12" class="main-text">GDPR</text>
</g>
<g transform="translate(0, 40)">
<rect x="0" y="0" width="14" height="14" rx="3" fill="#22c55e"/>
<text x="22" y="12" font-size="12" class="main-text">SOC 2</text>
</g>
<g transform="translate(0, 60)">
<rect x="0" y="0" width="14" height="14" rx="3" fill="#f97316"/>
<text x="22" y="12" font-size="12" class="main-text">HIPAA</text>
</g>
<g transform="translate(0, 80)">
<rect x="0" y="0" width="14" height="14" rx="3" fill="#22c55e"/>
<text x="22" y="12" font-size="12" class="main-text">ISO 27001</text>
</g>
</g>
<!-- Main Content Header -->
<g transform="translate(230, 55)">
<text x="0" y="20" font-size="18" font-weight="600" class="main-text">Security Overview</text>
<text x="0" y="40" font-size="13" class="secondary-text">Last scan: 5 minutes ago • Next scheduled: 24 hours</text>
<!-- Export Button -->
<g transform="translate(500, 5)">
<rect x="0" y="0" width="100" height="32" rx="6" class="icon-btn"/>
<rect x="0" y="0" width="100" height="32" rx="6" class="border"/>
<text x="50" y="21" text-anchor="middle" font-size="12" class="secondary-text">📄 Export</text>
</g>
</g>
<!-- Score Cards Row -->
<g transform="translate(230, 100)">
<!-- Overall Score -->
<rect x="0" y="0" width="145" height="90" rx="10" class="card-bg"/>
<rect x="0" y="0" width="145" height="90" rx="10" class="border"/>
<text x="15" y="25" font-size="11" class="secondary-text">Overall Score</text>
<text x="15" y="60" font-size="32" font-weight="700" class="green-text">87</text>
<text x="60" y="60" font-size="14" class="muted-text">/100</text>
<text x="15" y="78" font-size="11" class="green-text">↑ 5 pts</text>
<!-- Passed -->
<rect x="160" y="0" width="145" height="90" rx="10" class="card-bg"/>
<rect x="160" y="0" width="145" height="90" rx="10" class="border"/>
<text x="175" y="25" font-size="11" class="secondary-text">Passed</text>
<text x="175" y="60" font-size="32" font-weight="700" class="main-text">42</text>
<rect x="245" y="20" width="45" height="20" rx="10" class="status-pass"/>
<text x="267" y="34" text-anchor="middle" font-size="10" class="green-text">89%</text>
<!-- Warnings -->
<rect x="320" y="0" width="145" height="90" rx="10" class="card-bg"/>
<rect x="320" y="0" width="145" height="90" rx="10" class="border"/>
<text x="335" y="25" font-size="11" class="secondary-text">Warnings</text>
<text x="335" y="60" font-size="32" font-weight="700" class="orange-text">4</text>
<rect x="405" y="20" width="45" height="20" rx="10" class="status-warn"/>
<text x="427" y="34" text-anchor="middle" font-size="10" class="orange-text">8%</text>
<!-- Critical -->
<rect x="480" y="0" width="145" height="90" rx="10" class="card-bg"/>
<rect x="480" y="0" width="145" height="90" rx="10" class="border"/>
<text x="495" y="25" font-size="11" class="secondary-text">Critical</text>
<text x="495" y="60" font-size="32" font-weight="700" class="red-text">1</text>
<rect x="565" y="20" width="45" height="20" rx="10" class="status-fail"/>
<text x="587" y="34" text-anchor="middle" font-size="10" class="red-text">2%</text>
</g>
<!-- Issues List -->
<g transform="translate(230, 210)">
<text x="0" y="0" font-size="14" font-weight="600" class="main-text">Issues Found</text>
<!-- Critical Issue -->
<g transform="translate(0, 20)">
<rect x="0" y="0" width="610" height="65" rx="8" class="status-fail"/>
<rect x="0" y="0" width="610" height="65" rx="8" class="border"/>
<rect x="15" y="15" width="35" height="35" rx="8" fill="url(#redGrad)"/>
<text x="32" y="38" text-anchor="middle" font-size="14" class="white-text">🚨</text>
<text x="65" y="28" font-size="13" font-weight="600" class="main-text">Insecure API Endpoint Detected</text>
<text x="65" y="48" font-size="12" class="secondary-text">/api/v1/users lacks authentication • Found 2 hours ago</text>
<rect x="500" y="18" width="55" height="24" rx="6" class="icon-btn"/>
<text x="527" y="35" text-anchor="middle" font-size="11" class="red-text">Critical</text>
<rect x="560" y="18" width="35" height="24" rx="6" fill="url(#accentGrad)"/>
<text x="577" y="35" text-anchor="middle" font-size="11" class="white-text">Fix</text>
</g>
<!-- Warning Issue 1 -->
<g transform="translate(0, 95)">
<rect x="0" y="0" width="610" height="65" rx="8" class="status-warn"/>
<rect x="0" y="0" width="610" height="65" rx="8" class="border"/>
<rect x="15" y="15" width="35" height="35" rx="8" fill="url(#orangeGrad)"/>
<text x="32" y="38" text-anchor="middle" font-size="14" class="white-text">⚠️</text>
<text x="65" y="28" font-size="13" font-weight="600" class="main-text">Outdated SSL Certificate</text>
<text x="65" y="48" font-size="12" class="secondary-text">Certificate expires in 15 days • Renewal recommended</text>
<rect x="500" y="18" width="55" height="24" rx="6" class="icon-btn"/>
<text x="527" y="35" text-anchor="middle" font-size="11" class="orange-text">Warning</text>
<rect x="560" y="18" width="35" height="24" rx="6" fill="url(#accentGrad)"/>
<text x="577" y="35" text-anchor="middle" font-size="11" class="white-text">Fix</text>
</g>
<!-- Warning Issue 2 -->
<g transform="translate(0, 170)">
<rect x="0" y="0" width="610" height="65" rx="8" class="status-warn"/>
<rect x="0" y="0" width="610" height="65" rx="8" class="border"/>
<rect x="15" y="15" width="35" height="35" rx="8" fill="url(#orangeGrad)"/>
<text x="32" y="38" text-anchor="middle" font-size="14" class="white-text">⚠️</text>
<text x="65" y="28" font-size="13" font-weight="600" class="main-text">Missing Content Security Policy</text>
<text x="65" y="48" font-size="12" class="secondary-text">CSP header not configured • XSS vulnerability risk</text>
<rect x="500" y="18" width="55" height="24" rx="6" class="icon-btn"/>
<text x="527" y="35" text-anchor="middle" font-size="11" class="orange-text">Warning</text>
<rect x="560" y="18" width="35" height="24" rx="6" fill="url(#accentGrad)"/>
<text x="577" y="35" text-anchor="middle" font-size="11" class="white-text">Fix</text>
</g>
<!-- Passed Item -->
<g transform="translate(0, 245)">
<rect x="0" y="0" width="610" height="55" rx="8" class="status-pass"/>
<rect x="0" y="0" width="610" height="55" rx="8" class="border"/>
<rect x="15" y="10" width="35" height="35" rx="8" fill="url(#greenGrad)"/>
<text x="32" y="33" text-anchor="middle" font-size="14" class="white-text"></text>
<text x="65" y="25" font-size="13" font-weight="500" class="main-text">Data Encryption at Rest</text>
<text x="65" y="43" font-size="12" class="secondary-text">AES-256 encryption enabled • All data stores compliant</text>
<rect x="520" y="15" width="55" height="24" rx="6" class="icon-btn"/>
<text x="547" y="32" text-anchor="middle" font-size="11" class="green-text">Passed</text>
</g>
</g>
<!-- Compliance Progress Section -->
<g transform="translate(230, 480)">
<text x="0" y="0" font-size="14" font-weight="600" class="main-text">Compliance Progress</text>
<!-- GDPR Progress -->
<g transform="translate(0, 20)">
<text x="0" y="12" font-size="12" class="main-text">GDPR</text>
<rect x="80" y="3" width="200" height="12" rx="6" class="progress-bg"/>
<rect x="80" y="3" width="190" height="12" rx="6" fill="#22c55e"/>
<text x="290" y="14" font-size="12" class="green-text">95%</text>
</g>
<!-- SOC 2 Progress -->
<g transform="translate(0, 45)">
<text x="0" y="12" font-size="12" class="main-text">SOC 2</text>
<rect x="80" y="3" width="200" height="12" rx="6" class="progress-bg"/>
<rect x="80" y="3" width="180" height="12" rx="6" fill="#22c55e"/>
<text x="290" y="14" font-size="12" class="green-text">90%</text>
</g>
<!-- HIPAA Progress -->
<g transform="translate(350, 20)">
<text x="0" y="12" font-size="12" class="main-text">HIPAA</text>
<rect x="80" y="3" width="200" height="12" rx="6" class="progress-bg"/>
<rect x="80" y="3" width="150" height="12" rx="6" fill="#f97316"/>
<text x="290" y="14" font-size="12" class="orange-text">75%</text>
</g>
<!-- ISO 27001 Progress -->
<g transform="translate(350, 45)">
<text x="0" y="12" font-size="12" class="main-text">ISO 27001</text>
<rect x="80" y="3" width="200" height="12" rx="6" class="progress-bg"/>
<rect x="80" y="3" width="176" height="12" rx="6" fill="#22c55e"/>
<text x="290" y="14" font-size="12" class="green-text">88%</text>
</g>
</g>
<!-- Footer -->
<g transform="translate(230, 560)">
<text x="0" y="0" font-size="10" class="muted-text">R = Rescan | F = Filter by severity | E = Export report | Enter = View details</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -0,0 +1,279 @@
<svg width="900" height="600" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="accentGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#3b82f6"/>
<stop offset="100%" stop-color="#60a5fa"/>
</linearGradient>
<linearGradient id="greenGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#22c55e"/>
<stop offset="100%" stop-color="#4ade80"/>
</linearGradient>
<linearGradient id="purpleGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#8b5cf6"/>
<stop offset="100%" stop-color="#a78bfa"/>
</linearGradient>
<linearGradient id="orangeGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#f97316"/>
<stop offset="100%" stop-color="#fb923c"/>
</linearGradient>
<marker id="arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" fill="#94a3b8"/>
</marker>
</defs>
<style>
.bg { fill: #ffffff; }
.sidebar-bg { fill: #f8fafc; }
.canvas-bg { fill: #f1f5f9; }
.main-text { fill: #1e293b; font-family: system-ui, -apple-system, sans-serif; }
.secondary-text { fill: #64748b; font-family: system-ui, -apple-system, sans-serif; }
.muted-text { fill: #94a3b8; font-family: system-ui, -apple-system, sans-serif; }
.white-text { fill: #ffffff; font-family: system-ui, -apple-system, sans-serif; }
.accent-text { fill: #3b82f6; font-family: system-ui, -apple-system, sans-serif; }
.border { stroke: #e2e8f0; stroke-width: 1; fill: none; }
.icon-btn { fill: #f1f5f9; }
.node { fill: #ffffff; stroke: #e2e8f0; stroke-width: 2; }
.node-selected { fill: #ffffff; stroke: #3b82f6; stroke-width: 2; }
.connector { stroke: #94a3b8; stroke-width: 2; fill: none; }
.grid-dot { fill: #cbd5e1; }
@media (prefers-color-scheme: dark) {
.bg { fill: #0f172a; }
.sidebar-bg { fill: #1e293b; }
.canvas-bg { fill: #0f172a; }
.main-text { fill: #e2e8f0; }
.secondary-text { fill: #94a3b8; }
.muted-text { fill: #64748b; }
.accent-text { fill: #60a5fa; }
.border { stroke: #334155; }
.icon-btn { fill: #334155; }
.node { fill: #1e293b; stroke: #334155; }
.node-selected { fill: #1e293b; stroke: #3b82f6; }
.connector { stroke: #64748b; }
.grid-dot { fill: #334155; }
}
</style>
<text x="450" y="25" text-anchor="middle" font-size="16" font-weight="600" class="main-text">Designer - Visual Flow Builder</text>
<rect x="30" y="40" width="840" height="530" rx="8" class="bg"/>
<rect x="30" y="40" width="840" height="530" rx="8" class="border"/>
<!-- Left Toolbox Sidebar -->
<rect x="30" y="40" width="160" height="530" class="sidebar-bg"/>
<line x1="190" y1="40" x2="190" y2="570" class="border"/>
<text x="45" y="65" font-size="13" font-weight="600" class="main-text">Components</text>
<!-- Component Categories -->
<g transform="translate(45, 85)">
<!-- Triggers -->
<text x="0" y="0" font-size="11" font-weight="600" class="muted-text">TRIGGERS</text>
<g transform="translate(0, 15)">
<rect x="0" y="0" width="130" height="35" rx="6" class="icon-btn"/>
<rect x="10" y="8" width="20" height="20" rx="4" fill="url(#greenGrad)"/>
<text x="20" y="22" text-anchor="middle" font-size="10" class="white-text"></text>
<text x="40" y="23" font-size="11" class="main-text">Start</text>
</g>
<g transform="translate(0, 55)">
<rect x="0" y="0" width="130" height="35" rx="6" class="icon-btn"/>
<rect x="10" y="8" width="20" height="20" rx="4" fill="url(#accentGrad)"/>
<text x="20" y="22" text-anchor="middle" font-size="10" class="white-text">💬</text>
<text x="40" y="23" font-size="11" class="main-text">Message</text>
</g>
<!-- Actions -->
<text x="0" y="110" font-size="11" font-weight="600" class="muted-text">ACTIONS</text>
<g transform="translate(0, 125)">
<rect x="0" y="0" width="130" height="35" rx="6" class="icon-btn"/>
<rect x="10" y="8" width="20" height="20" rx="4" fill="url(#purpleGrad)"/>
<text x="20" y="22" text-anchor="middle" font-size="10" class="white-text">🤖</text>
<text x="40" y="23" font-size="11" class="main-text">AI Response</text>
</g>
<g transform="translate(0, 165)">
<rect x="0" y="0" width="130" height="35" rx="6" class="icon-btn"/>
<rect x="10" y="8" width="20" height="20" rx="4" fill="url(#orangeGrad)"/>
<text x="20" y="22" text-anchor="middle" font-size="10" class="white-text">📧</text>
<text x="40" y="23" font-size="11" class="main-text">Send Email</text>
</g>
<g transform="translate(0, 205)">
<rect x="0" y="0" width="130" height="35" rx="6" class="icon-btn"/>
<rect x="10" y="8" width="20" height="20" rx="4" fill="#ef4444"/>
<text x="20" y="22" text-anchor="middle" font-size="10" class="white-text"></text>
<text x="40" y="23" font-size="11" class="main-text">API Call</text>
</g>
<!-- Logic -->
<text x="0" y="260" font-size="11" font-weight="600" class="muted-text">LOGIC</text>
<g transform="translate(0, 275)">
<rect x="0" y="0" width="130" height="35" rx="6" class="icon-btn"/>
<rect x="10" y="8" width="20" height="20" rx="4" fill="#06b6d4"/>
<text x="20" y="22" text-anchor="middle" font-size="10" class="white-text"></text>
<text x="40" y="23" font-size="11" class="main-text">Condition</text>
</g>
<g transform="translate(0, 315)">
<rect x="0" y="0" width="130" height="35" rx="6" class="icon-btn"/>
<rect x="10" y="8" width="20" height="20" rx="4" fill="#ec4899"/>
<text x="20" y="22" text-anchor="middle" font-size="10" class="white-text"></text>
<text x="40" y="23" font-size="11" class="main-text">Wait</text>
</g>
<g transform="translate(0, 355)">
<rect x="0" y="0" width="130" height="35" rx="6" class="icon-btn"/>
<rect x="10" y="8" width="20" height="20" rx="4" fill="#64748b"/>
<text x="20" y="22" text-anchor="middle" font-size="10" class="white-text"></text>
<text x="40" y="23" font-size="11" class="main-text">End</text>
</g>
</g>
<!-- Canvas Area -->
<rect x="200" y="50" width="550" height="510" class="canvas-bg"/>
<!-- Toolbar -->
<g transform="translate(210, 60)">
<rect x="0" y="0" width="530" height="40" rx="8" class="bg"/>
<rect x="0" y="0" width="530" height="40" rx="8" class="border"/>
<rect x="10" y="7" width="70" height="26" rx="6" fill="url(#accentGrad)"/>
<text x="45" y="25" text-anchor="middle" font-size="11" class="white-text">+ Add</text>
<rect x="90" y="7" width="32" height="26" rx="6" class="icon-btn"/>
<text x="106" y="25" text-anchor="middle" font-size="14" class="secondary-text"></text>
<rect x="130" y="7" width="32" height="26" rx="6" class="icon-btn"/>
<text x="146" y="25" text-anchor="middle" font-size="14" class="secondary-text"></text>
<line x1="175" y1="10" x2="175" y2="30" class="border"/>
<rect x="185" y="7" width="32" height="26" rx="6" class="icon-btn"/>
<text x="201" y="25" text-anchor="middle" font-size="12" class="secondary-text">🔍</text>
<rect x="225" y="7" width="32" height="26" rx="6" class="icon-btn"/>
<text x="241" y="24" text-anchor="middle" font-size="14" class="secondary-text">+</text>
<rect x="265" y="7" width="32" height="26" rx="6" class="icon-btn"/>
<text x="281" y="25" text-anchor="middle" font-size="14" class="secondary-text"></text>
<text x="320" y="25" font-size="11" class="muted-text">100%</text>
<line x1="360" y1="10" x2="360" y2="30" class="border"/>
<rect x="370" y="7" width="70" height="26" rx="6" class="icon-btn"/>
<text x="405" y="25" text-anchor="middle" font-size="11" class="secondary-text">▶ Test</text>
<rect x="450" y="7" width="70" height="26" rx="6" fill="url(#greenGrad)"/>
<text x="485" y="25" text-anchor="middle" font-size="11" class="white-text">Deploy</text>
</g>
<!-- Grid Dots (decorative) -->
<g transform="translate(210, 110)">
<!-- Row 1 -->
<circle cx="20" cy="20" r="1.5" class="grid-dot"/>
<circle cx="60" cy="20" r="1.5" class="grid-dot"/>
<circle cx="100" cy="20" r="1.5" class="grid-dot"/>
<circle cx="140" cy="20" r="1.5" class="grid-dot"/>
<circle cx="180" cy="20" r="1.5" class="grid-dot"/>
<circle cx="220" cy="20" r="1.5" class="grid-dot"/>
<circle cx="260" cy="20" r="1.5" class="grid-dot"/>
<circle cx="300" cy="20" r="1.5" class="grid-dot"/>
<circle cx="340" cy="20" r="1.5" class="grid-dot"/>
<circle cx="380" cy="20" r="1.5" class="grid-dot"/>
<circle cx="420" cy="20" r="1.5" class="grid-dot"/>
<circle cx="460" cy="20" r="1.5" class="grid-dot"/>
<circle cx="500" cy="20" r="1.5" class="grid-dot"/>
</g>
<!-- Flow Nodes and Connections -->
<!-- Connection Lines -->
<path d="M310,195 L310,240" class="connector" marker-end="url(#arrowhead)"/>
<path d="M310,315 L310,360" class="connector" marker-end="url(#arrowhead)"/>
<path d="M310,435 L240,435 L240,480" class="connector" marker-end="url(#arrowhead)"/>
<path d="M310,435 L380,435 L380,480" class="connector" marker-end="url(#arrowhead)"/>
<!-- Start Node -->
<g transform="translate(235, 140)">
<rect x="0" y="0" width="150" height="55" rx="10" class="node"/>
<rect x="10" y="12" width="32" height="32" rx="8" fill="url(#greenGrad)"/>
<text x="26" y="34" text-anchor="middle" font-size="16" class="white-text"></text>
<text x="55" y="28" font-size="13" font-weight="500" class="main-text">Start</text>
<text x="55" y="44" font-size="10" class="secondary-text">User message</text>
</g>
<!-- AI Response Node (Selected) -->
<g transform="translate(235, 250)">
<rect x="0" y="0" width="150" height="65" rx="10" class="node-selected"/>
<rect x="10" y="12" width="32" height="32" rx="8" fill="url(#purpleGrad)"/>
<text x="26" y="34" text-anchor="middle" font-size="14" class="white-text">🤖</text>
<text x="55" y="28" font-size="13" font-weight="500" class="main-text">AI Response</text>
<text x="55" y="44" font-size="10" class="secondary-text">GPT-4 Model</text>
<circle cx="140" cy="32" r="6" fill="#3b82f6"/>
</g>
<!-- Condition Node -->
<g transform="translate(235, 370)">
<rect x="0" y="0" width="150" height="65" rx="10" class="node"/>
<rect x="10" y="12" width="32" height="32" rx="8" fill="#06b6d4"/>
<text x="26" y="34" text-anchor="middle" font-size="14" class="white-text"></text>
<text x="55" y="28" font-size="13" font-weight="500" class="main-text">Condition</text>
<text x="55" y="44" font-size="10" class="secondary-text">intent == support</text>
</g>
<!-- Send Email Node -->
<g transform="translate(165, 490)">
<rect x="0" y="0" width="150" height="55" rx="10" class="node"/>
<rect x="10" y="12" width="32" height="32" rx="8" fill="url(#orangeGrad)"/>
<text x="26" y="34" text-anchor="middle" font-size="12" class="white-text">📧</text>
<text x="55" y="28" font-size="13" font-weight="500" class="main-text">Send Email</text>
<text x="55" y="44" font-size="10" class="secondary-text">Support team</text>
</g>
<!-- End Node -->
<g transform="translate(305, 490)">
<rect x="0" y="0" width="150" height="55" rx="10" class="node"/>
<rect x="10" y="12" width="32" height="32" rx="8" fill="#64748b"/>
<text x="26" y="34" text-anchor="middle" font-size="14" class="white-text"></text>
<text x="55" y="28" font-size="13" font-weight="500" class="main-text">End</text>
<text x="55" y="44" font-size="10" class="secondary-text">Complete flow</text>
</g>
<!-- Right Properties Panel -->
<rect x="760" y="40" width="110" height="530" class="sidebar-bg"/>
<line x1="760" y1="40" x2="760" y2="570" class="border"/>
<text x="775" y="65" font-size="13" font-weight="600" class="main-text">Properties</text>
<g transform="translate(770, 85)">
<text x="0" y="0" font-size="10" font-weight="500" class="muted-text">NODE</text>
<text x="0" y="18" font-size="12" class="main-text">AI Response</text>
<text x="0" y="50" font-size="10" font-weight="500" class="muted-text">MODEL</text>
<rect x="0" y="58" width="90" height="28" rx="6" class="icon-btn"/>
<rect x="0" y="58" width="90" height="28" rx="6" class="border"/>
<text x="10" y="77" font-size="11" class="main-text">GPT-4</text>
<text x="75" y="77" font-size="10" class="muted-text"></text>
<text x="0" y="110" font-size="10" font-weight="500" class="muted-text">PROMPT</text>
<rect x="0" y="118" width="90" height="60" rx="6" class="icon-btn"/>
<rect x="0" y="118" width="90" height="60" rx="6" class="border"/>
<text x="8" y="136" font-size="10" class="secondary-text">You are a</text>
<text x="8" y="150" font-size="10" class="secondary-text">helpful</text>
<text x="8" y="164" font-size="10" class="secondary-text">assistant...</text>
<text x="0" y="200" font-size="10" font-weight="500" class="muted-text">TEMPERATURE</text>
<rect x="0" y="208" width="90" height="8" rx="4" fill="#e2e8f0"/>
<rect x="0" y="208" width="60" height="8" rx="4" fill="#3b82f6"/>
<text x="0" y="232" font-size="10" class="main-text">0.7</text>
</g>
<!-- Footer -->
<g transform="translate(210, 555)">
<text x="0" y="0" font-size="10" class="muted-text">Drag to connect | Del = Delete | Ctrl+D = Duplicate | Ctrl+Z = Undo</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -0,0 +1,187 @@
<svg width="900" height="600" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="accentGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#3b82f6"/>
<stop offset="100%" stop-color="#60a5fa"/>
</linearGradient>
</defs>
<style>
.bg { fill: #ffffff; }
.sidebar-bg { fill: #f8fafc; }
.header-bg { fill: #ffffff; }
.main-text { fill: #1e293b; font-family: system-ui, -apple-system, sans-serif; }
.secondary-text { fill: #64748b; font-family: system-ui, -apple-system, sans-serif; }
.muted-text { fill: #94a3b8; font-family: system-ui, -apple-system, sans-serif; }
.white-text { fill: #ffffff; font-family: system-ui, -apple-system, sans-serif; }
.accent-text { fill: #3b82f6; font-family: system-ui, -apple-system, sans-serif; }
.border { stroke: #e2e8f0; stroke-width: 1; fill: none; }
.icon-btn { fill: #f1f5f9; }
.folder-yellow { fill: #fbbf24; }
.file-blue { fill: #3b82f6; }
.file-green { fill: #22c55e; }
.file-red { fill: #ef4444; }
.row-hover { fill: #f1f5f9; }
.row-selected { fill: #eff6ff; }
.checkbox { fill: #ffffff; stroke: #cbd5e1; stroke-width: 1.5; }
.checkbox-checked { fill: #3b82f6; stroke: #3b82f6; stroke-width: 1.5; }
.storage-bar-bg { fill: #e2e8f0; }
.storage-bar-fill { fill: #3b82f6; }
@media (prefers-color-scheme: dark) {
.bg { fill: #0f172a; }
.sidebar-bg { fill: #1e293b; }
.header-bg { fill: #0f172a; }
.main-text { fill: #e2e8f0; }
.secondary-text { fill: #94a3b8; }
.muted-text { fill: #64748b; }
.accent-text { fill: #60a5fa; }
.border { stroke: #334155; }
.icon-btn { fill: #334155; }
.row-hover { fill: #1e293b; }
.row-selected { fill: #1e3a5f; }
.checkbox { fill: #1e293b; stroke: #475569; }
.storage-bar-bg { fill: #334155; }
}
</style>
<text x="450" y="25" text-anchor="middle" font-size="16" font-weight="600" class="main-text">Drive - File Manager</text>
<rect x="30" y="40" width="840" height="530" rx="8" class="bg"/>
<rect x="30" y="40" width="840" height="530" rx="8" class="border"/>
<rect x="30" y="40" width="180" height="530" class="sidebar-bg"/>
<line x1="210" y1="40" x2="210" y2="570" class="border"/>
<g transform="translate(45, 60)">
<rect x="0" y="0" width="150" height="40" rx="8" fill="url(#accentGrad)"/>
<text x="75" y="26" text-anchor="middle" font-size="14" font-weight="500" class="white-text">+ New</text>
</g>
<g transform="translate(45, 120)">
<rect x="-5" y="-8" width="160" height="36" rx="6" class="row-selected"/>
<text x="25" y="12" font-size="14" class="main-text">My Drive</text>
<text x="0" y="12" font-size="14">📁</text>
<text x="0" y="52" font-size="14">👥</text>
<text x="25" y="52" font-size="14" class="secondary-text">Shared with me</text>
<text x="0" y="92" font-size="14"></text>
<text x="25" y="92" font-size="14" class="secondary-text">Starred</text>
<text x="0" y="132" font-size="14">🕐</text>
<text x="25" y="132" font-size="14" class="secondary-text">Recent</text>
<text x="0" y="172" font-size="14">🗑️</text>
<text x="25" y="172" font-size="14" class="secondary-text">Trash</text>
</g>
<g transform="translate(45, 340)">
<text x="0" y="0" font-size="11" font-weight="600" class="muted-text">STORAGE</text>
<rect x="0" y="15" width="140" height="6" rx="3" class="storage-bar-bg"/>
<rect x="0" y="15" width="91" height="6" rx="3" class="storage-bar-fill"/>
<text x="0" y="38" font-size="11" class="secondary-text">6.5 GB of 10 GB</text>
</g>
<g transform="translate(230, 55)">
<rect x="0" y="0" width="300" height="36" rx="18" class="icon-btn"/>
<rect x="0" y="0" width="300" height="36" rx="18" class="border"/>
<text x="20" y="23" font-size="14">🔍</text>
<text x="45" y="24" font-size="13" class="muted-text">Search files...</text>
<rect x="320" y="0" width="36" height="36" rx="8" class="icon-btn"/>
<text x="338" y="24" text-anchor="middle" font-size="14"></text>
<rect x="365" y="0" width="36" height="36" rx="8" class="icon-btn"/>
<text x="383" y="24" text-anchor="middle" font-size="14"></text>
<rect x="410" y="0" width="36" height="36" rx="8" class="icon-btn"/>
<text x="428" y="24" text-anchor="middle" font-size="14"></text>
</g>
<g transform="translate(230, 105)">
<text x="0" y="0" font-size="13" class="secondary-text">My Drive</text>
<text x="55" y="0" font-size="13" class="muted-text">/</text>
<text x="65" y="0" font-size="13" class="secondary-text">Projects</text>
<text x="115" y="0" font-size="13" class="muted-text">/</text>
<text x="125" y="0" font-size="13" font-weight="500" class="main-text">2024</text>
</g>
<g transform="translate(230, 125)">
<rect x="0" y="0" width="620" height="32" rx="4" class="row-hover"/>
<text x="35" y="21" font-size="12" font-weight="500" class="secondary-text">Name</text>
<text x="350" y="21" font-size="12" font-weight="500" class="secondary-text">Modified</text>
<text x="480" y="21" font-size="12" font-weight="500" class="secondary-text">Size</text>
<text x="560" y="21" font-size="12" font-weight="500" class="secondary-text">Owner</text>
</g>
<g transform="translate(230, 165)">
<rect x="0" y="0" width="620" height="44" rx="4" class="row-selected"/>
<rect x="10" y="14" width="16" height="16" rx="3" class="checkbox-checked"/>
<text x="18" y="26" text-anchor="middle" font-size="10" class="white-text"></text>
<text x="35" y="28" font-size="18">📁</text>
<text x="60" y="28" font-size="14" class="main-text">Reports</text>
<text x="350" y="28" font-size="13" class="secondary-text">Today, 10:30 AM</text>
<text x="480" y="28" font-size="13" class="secondary-text"></text>
<text x="560" y="28" font-size="13" class="secondary-text">me</text>
</g>
<g transform="translate(230, 215)">
<rect x="0" y="0" width="620" height="44" rx="4" class="row-hover"/>
<rect x="10" y="14" width="16" height="16" rx="3" class="checkbox"/>
<text x="35" y="28" font-size="18">📁</text>
<text x="60" y="28" font-size="14" class="main-text">Presentations</text>
<text x="350" y="28" font-size="13" class="secondary-text">Yesterday</text>
<text x="480" y="28" font-size="13" class="secondary-text"></text>
<text x="560" y="28" font-size="13" class="secondary-text">me</text>
</g>
<g transform="translate(230, 265)">
<rect x="10" y="14" width="16" height="16" rx="3" class="checkbox"/>
<text x="35" y="28" font-size="18">📊</text>
<text x="60" y="28" font-size="14" class="main-text">Budget-2024.xlsx</text>
<text x="350" y="28" font-size="13" class="secondary-text">Mar 15, 2024</text>
<text x="480" y="28" font-size="13" class="secondary-text">245 KB</text>
<text x="560" y="28" font-size="13" class="secondary-text">me</text>
</g>
<g transform="translate(230, 310)">
<rect x="10" y="14" width="16" height="16" rx="3" class="checkbox"/>
<text x="35" y="28" font-size="18">📄</text>
<text x="60" y="28" font-size="14" class="main-text">Project-Proposal.docx</text>
<text x="350" y="28" font-size="13" class="secondary-text">Mar 14, 2024</text>
<text x="480" y="28" font-size="13" class="secondary-text">128 KB</text>
<text x="560" y="28" font-size="13" class="secondary-text">me</text>
</g>
<g transform="translate(230, 355)">
<rect x="10" y="14" width="16" height="16" rx="3" class="checkbox"/>
<text x="35" y="28" font-size="18">📕</text>
<text x="60" y="28" font-size="14" class="main-text">Contract-Signed.pdf</text>
<text x="350" y="28" font-size="13" class="secondary-text">Mar 10, 2024</text>
<text x="480" y="28" font-size="13" class="secondary-text">1.2 MB</text>
<text x="560" y="28" font-size="13" class="secondary-text">John D.</text>
</g>
<g transform="translate(230, 400)">
<rect x="10" y="14" width="16" height="16" rx="3" class="checkbox"/>
<text x="35" y="28" font-size="18">🖼️</text>
<text x="60" y="28" font-size="14" class="main-text">Logo-Final.png</text>
<text x="350" y="28" font-size="13" class="secondary-text">Mar 8, 2024</text>
<text x="480" y="28" font-size="13" class="secondary-text">89 KB</text>
<text x="560" y="28" font-size="13" class="secondary-text">me</text>
</g>
<g transform="translate(230, 470)">
<rect x="0" y="0" width="620" height="70" rx="8" fill="none" stroke="#3b82f6" stroke-width="2" stroke-dasharray="8,4"/>
<text x="310" y="30" text-anchor="middle" font-size="18">📤</text>
<text x="310" y="55" text-anchor="middle" font-size="13" class="secondary-text">Drop files here or click + New to upload</text>
</g>
<g transform="translate(230, 555)">
<text x="0" y="0" font-size="11" class="muted-text">1 item selected</text>
<text x="100" y="0" font-size="11" class="muted-text"></text>
<text x="115" y="0" font-size="11" class="muted-text">6 items</text>
<text x="350" y="0" font-size="10" class="muted-text">Ctrl+U Upload | Del Delete | Ctrl+C Copy</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9 KiB

View file

@ -0,0 +1,192 @@
<svg width="900" height="600" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="accentGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#3b82f6"/>
<stop offset="100%" stop-color="#60a5fa"/>
</linearGradient>
</defs>
<style>
.bg { fill: #ffffff; }
.panel-bg { fill: #f8fafc; }
.main-text { fill: #1e293b; font-family: system-ui, -apple-system, sans-serif; }
.secondary-text { fill: #64748b; font-family: system-ui, -apple-system, sans-serif; }
.muted-text { fill: #94a3b8; font-family: system-ui, -apple-system, sans-serif; }
.white-text { fill: #ffffff; font-family: system-ui, -apple-system, sans-serif; }
.accent-text { fill: #3b82f6; font-family: system-ui, -apple-system, sans-serif; }
.border { stroke: #e2e8f0; stroke-width: 1; fill: none; }
.icon-btn { fill: #f1f5f9; }
.row-hover { fill: #f1f5f9; }
.row-selected { fill: #eff6ff; }
.unread-bg { fill: #eff6ff; }
.unread-dot { fill: #3b82f6; }
.nav-active { fill: #eff6ff; }
@media (prefers-color-scheme: dark) {
.bg { fill: #0f172a; }
.panel-bg { fill: #1e293b; }
.main-text { fill: #e2e8f0; }
.secondary-text { fill: #94a3b8; }
.muted-text { fill: #64748b; }
.accent-text { fill: #60a5fa; }
.border { stroke: #334155; }
.icon-btn { fill: #334155; }
.row-hover { fill: #1e293b; }
.row-selected { fill: #1e3a5f; }
.unread-bg { fill: #1e3a5f; }
.nav-active { fill: #1e3a5f; }
}
</style>
<text x="450" y="25" text-anchor="middle" font-size="16" font-weight="600" class="main-text">Mail - Email Client</text>
<rect x="30" y="40" width="840" height="530" rx="8" class="bg"/>
<rect x="30" y="40" width="840" height="530" rx="8" class="border"/>
<!-- Sidebar Panel -->
<rect x="30" y="40" width="160" height="530" class="panel-bg"/>
<line x1="190" y1="40" x2="190" y2="570" class="border"/>
<!-- Compose Button -->
<g transform="translate(45, 55)">
<rect x="0" y="0" width="130" height="40" rx="8" fill="url(#accentGrad)"/>
<text x="65" y="26" text-anchor="middle" font-size="14" font-weight="500" class="white-text">✏ Compose</text>
</g>
<!-- Folder Navigation -->
<g transform="translate(45, 115)">
<rect x="-10" y="-8" width="150" height="36" rx="6" class="nav-active"/>
<text x="0" y="14" font-size="14">📥</text>
<text x="25" y="14" font-size="14" class="accent-text">Inbox</text>
<text x="115" y="14" font-size="12" class="accent-text">3</text>
<text x="0" y="54" font-size="14">📤</text>
<text x="25" y="54" font-size="14" class="secondary-text">Sent</text>
<text x="0" y="94" font-size="14">📝</text>
<text x="25" y="94" font-size="14" class="secondary-text">Drafts</text>
<text x="0" y="134" font-size="14"></text>
<text x="25" y="134" font-size="14" class="secondary-text">Starred</text>
<text x="0" y="174" font-size="14">🗑️</text>
<text x="25" y="174" font-size="14" class="secondary-text">Trash</text>
</g>
<!-- Mail List Panel -->
<rect x="190" y="40" width="280" height="530" class="bg"/>
<line x1="470" y1="40" x2="470" y2="570" class="border"/>
<!-- Mail List Header -->
<g transform="translate(205, 55)">
<text x="0" y="15" font-size="16" font-weight="600" class="main-text">Inbox</text>
<rect x="200" y="0" width="50" height="28" rx="6" class="icon-btn"/>
<text x="225" y="19" text-anchor="middle" font-size="12">🔄</text>
</g>
<line x1="190" y1="85" x2="470" y2="85" class="border"/>
<!-- Mail Items -->
<g transform="translate(200, 95)">
<!-- Unread Email 1 -->
<rect x="0" y="0" width="260" height="75" rx="4" class="unread-bg"/>
<circle cx="12" cy="37" r="4" class="unread-dot"/>
<text x="25" y="20" font-size="13" font-weight="600" class="main-text">Sarah Johnson</text>
<text x="180" y="20" font-size="11" class="muted-text">10:30 AM</text>
<text x="25" y="40" font-size="12" font-weight="500" class="main-text">Project Update</text>
<text x="25" y="58" font-size="12" class="secondary-text">Hi team, here is the latest...</text>
</g>
<g transform="translate(200, 175)">
<!-- Unread Email 2 -->
<rect x="0" y="0" width="260" height="75" rx="4" class="unread-bg"/>
<circle cx="12" cy="37" r="4" class="unread-dot"/>
<text x="25" y="20" font-size="13" font-weight="600" class="main-text">Marketing Team</text>
<text x="180" y="20" font-size="11" class="muted-text">9:15 AM</text>
<text x="25" y="40" font-size="12" font-weight="500" class="main-text">Q4 Campaign Results</text>
<text x="25" y="58" font-size="12" class="secondary-text">The numbers are in and...</text>
</g>
<g transform="translate(200, 255)">
<!-- Selected Email -->
<rect x="0" y="0" width="260" height="75" rx="4" class="row-selected"/>
<rect x="0" y="0" width="3" height="75" rx="1" fill="#3b82f6"/>
<text x="25" y="20" font-size="13" font-weight="500" class="main-text">John Smith</text>
<text x="180" y="20" font-size="11" class="muted-text">Yesterday</text>
<text x="25" y="40" font-size="12" class="main-text">Meeting Notes</text>
<text x="25" y="58" font-size="12" class="secondary-text">Thanks for the call today...</text>
</g>
<g transform="translate(200, 335)">
<!-- Read Email -->
<text x="25" y="20" font-size="13" class="secondary-text">Alex Chen</text>
<text x="180" y="20" font-size="11" class="muted-text">Mar 15</text>
<text x="25" y="40" font-size="12" class="secondary-text">Re: Budget Review</text>
<text x="25" y="58" font-size="12" class="muted-text">Looks good to me...</text>
</g>
<g transform="translate(200, 405)">
<text x="25" y="20" font-size="13" class="secondary-text">HR Department</text>
<text x="180" y="20" font-size="11" class="muted-text">Mar 14</text>
<text x="25" y="40" font-size="12" class="secondary-text">Benefits Enrollment</text>
<text x="25" y="58" font-size="12" class="muted-text">Open enrollment starts...</text>
</g>
<!-- Mail Content Panel -->
<rect x="470" y="40" width="400" height="530" class="bg"/>
<!-- Email Header -->
<g transform="translate(490, 60)">
<text x="0" y="20" font-size="18" font-weight="600" class="main-text">Meeting Notes</text>
<g transform="translate(0, 40)">
<circle cx="18" cy="18" r="18" fill="#22c55e"/>
<text x="18" y="23" text-anchor="middle" font-size="12" font-weight="600" class="white-text">JS</text>
<text x="45" y="12" font-size="14" font-weight="500" class="main-text">John Smith</text>
<text x="45" y="30" font-size="12" class="secondary-text">john.smith@company.com</text>
<text x="300" y="20" font-size="12" class="muted-text">Yesterday, 3:45 PM</text>
</g>
</g>
<line x1="490" y1="145" x2="850" y2="145" class="border"/>
<!-- Email Actions -->
<g transform="translate(490, 155)">
<rect x="0" y="0" width="70" height="32" rx="6" class="icon-btn"/>
<text x="35" y="21" text-anchor="middle" font-size="12" class="secondary-text">↩ Reply</text>
<rect x="80" y="0" width="80" height="32" rx="6" class="icon-btn"/>
<text x="120" y="21" text-anchor="middle" font-size="12" class="secondary-text">↩↩ Reply All</text>
<rect x="170" y="0" width="75" height="32" rx="6" class="icon-btn"/>
<text x="207" y="21" text-anchor="middle" font-size="12" class="secondary-text">↪ Forward</text>
<rect x="255" y="0" width="60" height="32" rx="6" class="icon-btn"/>
<text x="285" y="21" text-anchor="middle" font-size="12" class="secondary-text">🗑 Delete</text>
</g>
<line x1="490" y1="200" x2="850" y2="200" class="border"/>
<!-- Email Body -->
<g transform="translate(490, 220)">
<text x="0" y="0" font-size="14" class="main-text">Hi Team,</text>
<text x="0" y="30" font-size="14" class="main-text">Thanks for joining the call today. Here are the key</text>
<text x="0" y="50" font-size="14" class="main-text">takeaways from our discussion:</text>
<text x="0" y="90" font-size="14" class="main-text">• Project timeline updated to Q2 launch</text>
<text x="0" y="115" font-size="14" class="main-text">• Budget approved for additional resources</text>
<text x="0" y="140" font-size="14" class="main-text">• Next review scheduled for Friday</text>
<text x="0" y="180" font-size="14" class="main-text">Let me know if you have any questions.</text>
<text x="0" y="220" font-size="14" class="main-text">Best regards,</text>
<text x="0" y="240" font-size="14" class="main-text">John</text>
</g>
<!-- Footer -->
<g transform="translate(490, 540)">
<text x="0" y="0" font-size="10" class="muted-text">Ctrl+R Reply | Ctrl+Shift+R Reply All | Ctrl+F Forward | Del Delete</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.6 KiB

View file

@ -0,0 +1,185 @@
<svg width="900" height="600" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="accentGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#3b82f6"/>
<stop offset="100%" stop-color="#60a5fa"/>
</linearGradient>
<linearGradient id="endCallGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#ef4444"/>
<stop offset="100%" stop-color="#dc2626"/>
</linearGradient>
</defs>
<style>
.bg { fill: #0f172a; }
.panel-bg { fill: #1e293b; }
.main-text { fill: #e2e8f0; font-family: system-ui, -apple-system, sans-serif; }
.secondary-text { fill: #94a3b8; font-family: system-ui, -apple-system, sans-serif; }
.muted-text { fill: #64748b; font-family: system-ui, -apple-system, sans-serif; }
.white-text { fill: #ffffff; font-family: system-ui, -apple-system, sans-serif; }
.accent-text { fill: #60a5fa; font-family: system-ui, -apple-system, sans-serif; }
.border { stroke: #334155; stroke-width: 1; fill: none; }
.control-btn { fill: #334155; }
.control-btn-active { fill: #3b82f6; }
.control-btn-off { fill: #ef4444; }
.video-bg { fill: #1e293b; }
.participant-border { stroke: #3b82f6; stroke-width: 2; fill: none; }
.speaking-border { stroke: #22c55e; stroke-width: 3; fill: none; }
.muted-indicator { fill: #ef4444; }
.online-dot { fill: #22c55e; }
@media (prefers-color-scheme: light) {
.bg { fill: #f1f5f9; }
.panel-bg { fill: #ffffff; }
.main-text { fill: #1e293b; }
.secondary-text { fill: #64748b; }
.muted-text { fill: #94a3b8; }
.border { stroke: #e2e8f0; }
.control-btn { fill: #e2e8f0; }
.video-bg { fill: #e2e8f0; }
}
</style>
<text x="450" y="25" text-anchor="middle" font-size="16" font-weight="600" class="main-text">Meet - Video Conference</text>
<rect x="30" y="40" width="840" height="530" rx="8" class="bg"/>
<rect x="30" y="40" width="840" height="530" rx="8" class="border"/>
<!-- Main Video Area -->
<rect x="45" y="55" width="620" height="420" rx="12" class="video-bg"/>
<rect x="45" y="55" width="620" height="420" rx="12" class="speaking-border"/>
<!-- Main Speaker Avatar/Video -->
<circle cx="355" cy="230" r="80" fill="#3b82f6"/>
<text x="355" y="250" text-anchor="middle" font-size="48" class="white-text">JS</text>
<text x="355" y="340" text-anchor="middle" font-size="18" font-weight="500" class="main-text">John Smith</text>
<text x="355" y="365" text-anchor="middle" font-size="14" class="secondary-text">Speaking...</text>
<!-- Speaking indicator animation dots -->
<g transform="translate(315, 380)">
<circle cx="0" cy="0" r="4" class="online-dot" opacity="0.4"/>
<circle cx="15" cy="0" r="4" class="online-dot" opacity="0.7"/>
<circle cx="30" cy="0" r="4" class="online-dot"/>
<circle cx="45" cy="0" r="4" class="online-dot" opacity="0.7"/>
<circle cx="60" cy="0" r="4" class="online-dot" opacity="0.4"/>
</g>
<!-- Meeting Info Overlay -->
<g transform="translate(60, 70)">
<rect x="0" y="0" width="200" height="30" rx="6" fill="#0f172a" opacity="0.7"/>
<circle cx="15" cy="15" r="5" class="online-dot"/>
<text x="28" y="20" font-size="13" class="main-text">Team Standup • 15:32</text>
</g>
<!-- Self View (Picture-in-Picture) -->
<rect x="500" y="370" width="150" height="95" rx="8" class="video-bg"/>
<rect x="500" y="370" width="150" height="95" rx="8" class="participant-border"/>
<circle cx="575" cy="410" r="25" fill="#8b5cf6"/>
<text x="575" y="418" text-anchor="middle" font-size="18" class="white-text">ME</text>
<text x="575" y="455" text-anchor="middle" font-size="11" class="main-text">You</text>
<!-- Participants Sidebar -->
<rect x="680" y="55" width="175" height="420" rx="8" class="panel-bg"/>
<rect x="680" y="55" width="175" height="420" rx="8" class="border"/>
<text x="695" y="80" font-size="14" font-weight="600" class="main-text">Participants (5)</text>
<!-- Participant 1 -->
<g transform="translate(695, 95)">
<rect x="0" y="0" width="145" height="65" rx="6" class="video-bg"/>
<circle cx="35" cy="32" r="20" fill="#22c55e"/>
<text x="35" y="40" text-anchor="middle" font-size="14" class="white-text">SW</text>
<text x="65" y="28" font-size="12" class="main-text">Sarah Wilson</text>
<circle cx="65" cy="42" r="4" class="online-dot"/>
<text x="75" y="45" font-size="10" class="secondary-text">Online</text>
</g>
<!-- Participant 2 -->
<g transform="translate(695, 170)">
<rect x="0" y="0" width="145" height="65" rx="6" class="video-bg"/>
<circle cx="35" cy="32" r="20" fill="#f97316"/>
<text x="35" y="40" text-anchor="middle" font-size="14" class="white-text">MJ</text>
<text x="65" y="28" font-size="12" class="main-text">Mike Johnson</text>
<circle cx="65" cy="42" r="4" class="muted-indicator"/>
<text x="75" y="45" font-size="10" class="secondary-text">Muted</text>
</g>
<!-- Participant 3 -->
<g transform="translate(695, 245)">
<rect x="0" y="0" width="145" height="65" rx="6" class="video-bg"/>
<circle cx="35" cy="32" r="20" fill="#ec4899"/>
<text x="35" y="40" text-anchor="middle" font-size="14" class="white-text">AC</text>
<text x="65" y="28" font-size="12" class="main-text">Alex Chen</text>
<circle cx="65" cy="42" r="4" class="online-dot"/>
<text x="75" y="45" font-size="10" class="secondary-text">Online</text>
</g>
<!-- Participant 4 -->
<g transform="translate(695, 320)">
<rect x="0" y="0" width="145" height="65" rx="6" class="video-bg"/>
<circle cx="35" cy="32" r="20" fill="#14b8a6"/>
<text x="35" y="40" text-anchor="middle" font-size="14" class="white-text">EM</text>
<text x="65" y="28" font-size="12" class="main-text">Emma Miller</text>
<circle cx="65" cy="42" r="4" class="online-dot"/>
<text x="75" y="45" font-size="10" class="secondary-text">Online</text>
</g>
<!-- Invite Button -->
<g transform="translate(695, 400)">
<rect x="0" y="0" width="145" height="35" rx="6" fill="url(#accentGrad)"/>
<text x="72" y="23" text-anchor="middle" font-size="12" font-weight="500" class="white-text">+ Invite People</text>
</g>
<!-- Bottom Control Bar -->
<rect x="45" y="490" width="810" height="70" rx="8" class="panel-bg"/>
<rect x="45" y="490" width="810" height="70" rx="8" class="border"/>
<!-- Left Controls - Meeting Info -->
<g transform="translate(70, 510)">
<text x="0" y="15" font-size="14" font-weight="500" class="main-text">Team Standup</text>
<text x="0" y="35" font-size="12" class="secondary-text">5 participants • 15:32</text>
</g>
<!-- Center Controls -->
<g transform="translate(350, 505)">
<!-- Microphone (On) -->
<circle cx="0" cy="25" r="25" class="control-btn"/>
<text x="0" y="32" text-anchor="middle" font-size="18">🎤</text>
<!-- Camera (On) -->
<circle cx="65" cy="25" r="25" class="control-btn"/>
<text x="65" y="32" text-anchor="middle" font-size="18">📹</text>
<!-- Screen Share -->
<circle cx="130" cy="25" r="25" class="control-btn"/>
<text x="130" y="32" text-anchor="middle" font-size="18">🖥</text>
<!-- Chat -->
<circle cx="195" cy="25" r="25" class="control-btn"/>
<text x="195" y="32" text-anchor="middle" font-size="18">💬</text>
<!-- End Call -->
<circle cx="275" cy="25" r="28" fill="url(#endCallGrad)"/>
<text x="275" y="32" text-anchor="middle" font-size="18">📞</text>
</g>
<!-- Right Controls -->
<g transform="translate(720, 505)">
<!-- More Options -->
<circle cx="0" cy="25" r="22" class="control-btn"/>
<text x="0" y="32" text-anchor="middle" font-size="16"></text>
<!-- Fullscreen -->
<circle cx="55" cy="25" r="22" class="control-btn"/>
<text x="55" y="32" text-anchor="middle" font-size="16"></text>
<!-- Layout -->
<circle cx="110" cy="25" r="22" class="control-btn"/>
<text x="110" y="32" text-anchor="middle" font-size="16"></text>
</g>
<!-- Footer -->
<g transform="translate(50, 575)">
<text x="0" y="0" font-size="10" class="muted-text">M = Mute | V = Camera | S = Share Screen | C = Chat | L = Leave</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.1 KiB

View file

@ -0,0 +1,209 @@
<svg width="900" height="600" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="accentGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#3b82f6"/>
<stop offset="100%" stop-color="#60a5fa"/>
</linearGradient>
</defs>
<style>
.bg { fill: #ffffff; }
.sidebar-bg { fill: #f8fafc; }
.main-text { fill: #1e293b; font-family: system-ui, -apple-system, sans-serif; }
.secondary-text { fill: #64748b; font-family: system-ui, -apple-system, sans-serif; }
.muted-text { fill: #94a3b8; font-family: system-ui, -apple-system, sans-serif; }
.white-text { fill: #ffffff; font-family: system-ui, -apple-system, sans-serif; }
.accent-text { fill: #3b82f6; font-family: system-ui, -apple-system, sans-serif; }
.border { stroke: #e2e8f0; stroke-width: 1; fill: none; }
.icon-btn { fill: #f1f5f9; }
.toolbar-bg { fill: #f8fafc; }
.ai-suggestion { fill: #eff6ff; stroke: #3b82f6; stroke-width: 1; }
.cursor { stroke: #3b82f6; stroke-width: 2; }
@media (prefers-color-scheme: dark) {
.bg { fill: #0f172a; }
.sidebar-bg { fill: #1e293b; }
.main-text { fill: #e2e8f0; }
.secondary-text { fill: #94a3b8; }
.muted-text { fill: #64748b; }
.accent-text { fill: #60a5fa; }
.border { stroke: #334155; }
.icon-btn { fill: #334155; }
.toolbar-bg { fill: #1e293b; }
.ai-suggestion { fill: #1e3a5f; stroke: #3b82f6; }
}
</style>
<text x="450" y="25" text-anchor="middle" font-size="16" font-weight="600" class="main-text">Paper - AI Writing Assistant</text>
<rect x="30" y="40" width="840" height="530" rx="8" class="bg"/>
<rect x="30" y="40" width="840" height="530" rx="8" class="border"/>
<!-- Sidebar -->
<rect x="30" y="40" width="180" height="530" class="sidebar-bg"/>
<line x1="210" y1="40" x2="210" y2="570" class="border"/>
<!-- New Document Button -->
<g transform="translate(45, 55)">
<rect x="0" y="0" width="150" height="40" rx="8" fill="url(#accentGrad)"/>
<text x="75" y="26" text-anchor="middle" font-size="14" font-weight="500" class="white-text">+ New Document</text>
</g>
<!-- Documents List -->
<g transform="translate(45, 115)">
<text x="0" y="0" font-size="11" font-weight="600" class="muted-text">RECENT DOCUMENTS</text>
<g transform="translate(0, 20)">
<rect x="-10" y="-8" width="160" height="40" rx="6" fill="#eff6ff"/>
<text x="0" y="8" font-size="13">📄</text>
<text x="22" y="8" font-size="13" class="accent-text">Project Proposal</text>
<text x="22" y="24" font-size="10" class="muted-text">Edited 2 min ago</text>
</g>
<g transform="translate(0, 70)">
<text x="0" y="8" font-size="13">📄</text>
<text x="22" y="8" font-size="13" class="main-text">Meeting Notes</text>
<text x="22" y="24" font-size="10" class="muted-text">Edited yesterday</text>
</g>
<g transform="translate(0, 115)">
<text x="0" y="8" font-size="13">📄</text>
<text x="22" y="8" font-size="13" class="main-text">Q4 Report Draft</text>
<text x="22" y="24" font-size="10" class="muted-text">Edited Mar 14</text>
</g>
<g transform="translate(0, 160)">
<text x="0" y="8" font-size="13">📄</text>
<text x="22" y="8" font-size="13" class="main-text">Blog Post Ideas</text>
<text x="22" y="24" font-size="10" class="muted-text">Edited Mar 12</text>
</g>
</g>
<!-- Templates Section -->
<g transform="translate(45, 340)">
<text x="0" y="0" font-size="11" font-weight="600" class="muted-text">TEMPLATES</text>
<g transform="translate(0, 20)">
<text x="0" y="12" font-size="13">📝</text>
<text x="22" y="12" font-size="13" class="secondary-text">Blank Document</text>
</g>
<g transform="translate(0, 45)">
<text x="0" y="12" font-size="13">📋</text>
<text x="22" y="12" font-size="13" class="secondary-text">Meeting Notes</text>
</g>
<g transform="translate(0, 70)">
<text x="0" y="12" font-size="13">📊</text>
<text x="22" y="12" font-size="13" class="secondary-text">Report</text>
</g>
<g transform="translate(0, 95)">
<text x="0" y="12" font-size="13">📧</text>
<text x="22" y="12" font-size="13" class="secondary-text">Email Draft</text>
</g>
</g>
<!-- Main Editor Area -->
<rect x="220" y="50" width="640" height="510" class="bg"/>
<!-- Toolbar -->
<rect x="230" y="55" width="620" height="45" rx="8" class="toolbar-bg"/>
<rect x="230" y="55" width="620" height="45" rx="8" class="border"/>
<g transform="translate(245, 65)">
<!-- Format buttons -->
<rect x="0" y="0" width="28" height="26" rx="4" class="icon-btn"/>
<text x="14" y="18" text-anchor="middle" font-size="14" font-weight="700" class="main-text">B</text>
<rect x="35" y="0" width="28" height="26" rx="4" class="icon-btn"/>
<text x="49" y="18" text-anchor="middle" font-size="14" font-style="italic" class="main-text">I</text>
<rect x="70" y="0" width="28" height="26" rx="4" class="icon-btn"/>
<text x="84" y="18" text-anchor="middle" font-size="14" text-decoration="underline" class="main-text">U</text>
<line x1="110" y1="3" x2="110" y2="23" class="border"/>
<!-- Heading selector -->
<rect x="120" y="0" width="70" height="26" rx="4" class="icon-btn"/>
<text x="155" y="18" text-anchor="middle" font-size="12" class="secondary-text">Heading ▾</text>
<line x1="200" y1="3" x2="200" y2="23" class="border"/>
<!-- List buttons -->
<rect x="210" y="0" width="28" height="26" rx="4" class="icon-btn"/>
<text x="224" y="18" text-anchor="middle" font-size="14" class="main-text"></text>
<rect x="245" y="0" width="28" height="26" rx="4" class="icon-btn"/>
<text x="259" y="18" text-anchor="middle" font-size="14" class="main-text"></text>
<line x1="285" y1="3" x2="285" y2="23" class="border"/>
<!-- Link and Image -->
<rect x="295" y="0" width="28" height="26" rx="4" class="icon-btn"/>
<text x="309" y="18" text-anchor="middle" font-size="12" class="main-text">🔗</text>
<rect x="330" y="0" width="28" height="26" rx="4" class="icon-btn"/>
<text x="344" y="18" text-anchor="middle" font-size="12" class="main-text">🖼</text>
<line x1="370" y1="3" x2="370" y2="23" class="border"/>
<!-- AI Assist Button -->
<rect x="380" y="0" width="100" height="26" rx="13" fill="url(#accentGrad)"/>
<text x="430" y="18" text-anchor="middle" font-size="12" font-weight="500" class="white-text">✨ AI Assist</text>
<!-- More options -->
<rect x="560" y="0" width="28" height="26" rx="4" class="icon-btn"/>
<text x="574" y="18" text-anchor="middle" font-size="14" class="secondary-text"></text>
</g>
<!-- Document Title -->
<g transform="translate(250, 120)">
<text x="0" y="0" font-size="28" font-weight="700" class="main-text">Project Proposal</text>
<text x="0" y="25" font-size="13" class="muted-text">Last edited 2 minutes ago • Auto-saved</text>
</g>
<!-- Document Content -->
<g transform="translate(250, 180)">
<text x="0" y="0" font-size="18" font-weight="600" class="main-text">Executive Summary</text>
<text x="0" y="35" font-size="14" class="main-text">This proposal outlines a comprehensive strategy for improving</text>
<text x="0" y="55" font-size="14" class="main-text">our customer engagement platform. The project aims to increase</text>
<text x="0" y="75" font-size="14" class="main-text">user retention by 25% and reduce support tickets by 40%.</text>
<text x="0" y="115" font-size="18" font-weight="600" class="main-text">Key Objectives</text>
<text x="0" y="150" font-size="14" class="main-text">• Redesign the onboarding experience for new users</text>
<text x="0" y="175" font-size="14" class="main-text">• Implement AI-powered customer support chatbot</text>
<text x="0" y="200" font-size="14" class="main-text">• Create personalized dashboard for each user segment</text>
<text x="0" y="225" font-size="14" class="main-text">• Integrate analytics tracking for better insights|</text>
<!-- Cursor -->
<line x1="445" y1="213" x2="445" y2="230" class="cursor"/>
</g>
<!-- AI Suggestion Panel -->
<g transform="translate(250, 420)">
<rect x="0" y="0" width="580" height="90" rx="8" class="ai-suggestion"/>
<text x="15" y="22" font-size="12" font-weight="600" class="accent-text">✨ AI Suggestion</text>
<text x="15" y="45" font-size="13" class="main-text">Consider adding a timeline section to outline project milestones</text>
<text x="15" y="63" font-size="13" class="main-text">and deliverables. This helps stakeholders understand the scope.</text>
<g transform="translate(15, 70)">
<rect x="0" y="0" width="70" height="24" rx="12" fill="url(#accentGrad)"/>
<text x="35" y="16" text-anchor="middle" font-size="11" class="white-text">Insert</text>
<rect x="80" y="0" width="70" height="24" rx="12" class="icon-btn"/>
<text x="115" y="16" text-anchor="middle" font-size="11" class="secondary-text">Dismiss</text>
<rect x="160" y="0" width="90" height="24" rx="12" class="icon-btn"/>
<text x="205" y="16" text-anchor="middle" font-size="11" class="secondary-text">Regenerate</text>
</g>
</g>
<!-- Word Count Footer -->
<g transform="translate(250, 530)">
<text x="0" y="0" font-size="11" class="muted-text">324 words • 1,847 characters • Reading time: 2 min</text>
<text x="380" y="0" font-size="10" class="muted-text">Ctrl+S Save | Ctrl+B Bold | Ctrl+I Italic | Ctrl+K Link</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.5 KiB

View file

@ -0,0 +1,203 @@
<svg width="900" height="600" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="accentGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#3b82f6"/>
<stop offset="100%" stop-color="#60a5fa"/>
</linearGradient>
<linearGradient id="overlayGrad" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="rgba(0,0,0,0)"/>
<stop offset="100%" stop-color="rgba(0,0,0,0.7)"/>
</linearGradient>
</defs>
<style>
.bg { fill: #0f172a; }
.sidebar-bg { fill: #1e293b; }
.main-text { fill: #e2e8f0; font-family: system-ui, -apple-system, sans-serif; }
.secondary-text { fill: #94a3b8; font-family: system-ui, -apple-system, sans-serif; }
.muted-text { fill: #64748b; font-family: system-ui, -apple-system, sans-serif; }
.white-text { fill: #ffffff; font-family: system-ui, -apple-system, sans-serif; }
.accent-text { fill: #60a5fa; font-family: system-ui, -apple-system, sans-serif; }
.border { stroke: #334155; stroke-width: 1; fill: none; }
.icon-btn { fill: #334155; }
.control-btn { fill: rgba(255,255,255,0.1); }
.progress-bg { fill: #334155; }
.progress-fill { fill: #3b82f6; }
.thumbnail { fill: #1e293b; stroke: #334155; stroke-width: 1; }
.thumbnail-active { fill: #1e293b; stroke: #3b82f6; stroke-width: 2; }
.viewer-bg { fill: #0f172a; }
@media (prefers-color-scheme: light) {
.bg { fill: #f8fafc; }
.sidebar-bg { fill: #ffffff; }
.main-text { fill: #1e293b; }
.secondary-text { fill: #64748b; }
.muted-text { fill: #94a3b8; }
.accent-text { fill: #3b82f6; }
.border { stroke: #e2e8f0; }
.icon-btn { fill: #f1f5f9; }
.control-btn { fill: rgba(0,0,0,0.1); }
.progress-bg { fill: #e2e8f0; }
.thumbnail { fill: #f1f5f9; stroke: #e2e8f0; }
.thumbnail-active { fill: #f1f5f9; stroke: #3b82f6; }
.viewer-bg { fill: #1e293b; }
}
</style>
<text x="450" y="25" text-anchor="middle" font-size="16" font-weight="600" class="main-text">Player - Media Viewer</text>
<rect x="30" y="40" width="840" height="530" rx="8" class="bg"/>
<rect x="30" y="40" width="840" height="530" rx="8" class="border"/>
<!-- Main Viewer Area -->
<rect x="40" y="50" width="640" height="400" rx="8" class="viewer-bg"/>
<!-- Slide Content Area -->
<rect x="60" y="70" width="600" height="340" rx="4" fill="#1e293b"/>
<!-- Slide Content (Presentation) -->
<g transform="translate(80, 90)">
<text x="0" y="0" font-size="28" font-weight="700" class="white-text">Q4 2024 Business Review</text>
<text x="0" y="40" font-size="16" class="secondary-text">Strategic Initiatives and Key Metrics</text>
<!-- Bullet points -->
<text x="0" y="100" font-size="18" class="main-text">• Revenue grew 23% year-over-year</text>
<text x="0" y="135" font-size="18" class="main-text">• Customer satisfaction score: 94%</text>
<text x="0" y="170" font-size="18" class="main-text">• New product launches: 3</text>
<text x="0" y="205" font-size="18" class="main-text">• Market expansion into APAC region</text>
<!-- Simple chart representation -->
<rect x="350" y="80" width="180" height="150" rx="8" fill="#334155"/>
<text x="440" y="105" text-anchor="middle" font-size="12" class="secondary-text">Revenue Trend</text>
<!-- Bar chart -->
<rect x="375" y="170" width="25" height="40" rx="2" fill="#3b82f6"/>
<rect x="410" y="150" width="25" height="60" rx="2" fill="#3b82f6"/>
<rect x="445" y="130" width="25" height="80" rx="2" fill="#3b82f6"/>
<rect x="480" y="115" width="25" height="95" rx="2" fill="#22c55e"/>
<text x="387" y="225" text-anchor="middle" font-size="9" class="muted-text">Q1</text>
<text x="422" y="225" text-anchor="middle" font-size="9" class="muted-text">Q2</text>
<text x="457" y="225" text-anchor="middle" font-size="9" class="muted-text">Q3</text>
<text x="492" y="225" text-anchor="middle" font-size="9" class="muted-text">Q4</text>
</g>
<!-- Slide Number -->
<rect x="580" y="375" width="60" height="25" rx="12" fill="rgba(0,0,0,0.5)"/>
<text x="610" y="392" text-anchor="middle" font-size="12" class="white-text">5 / 12</text>
<!-- Video Controls Bar -->
<rect x="40" y="460" width="640" height="60" rx="8" class="sidebar-bg"/>
<rect x="40" y="460" width="640" height="60" rx="8" class="border"/>
<!-- Play/Pause Controls -->
<g transform="translate(60, 475)">
<!-- Previous -->
<circle cx="0" cy="15" r="15" class="control-btn"/>
<text x="0" y="20" text-anchor="middle" font-size="14" class="main-text"></text>
<!-- Play/Pause -->
<circle cx="50" cy="15" r="20" fill="url(#accentGrad)"/>
<text x="50" y="22" text-anchor="middle" font-size="18" class="white-text"></text>
<!-- Next -->
<circle cx="100" cy="15" r="15" class="control-btn"/>
<text x="100" y="20" text-anchor="middle" font-size="14" class="main-text"></text>
</g>
<!-- Progress Bar -->
<g transform="translate(180, 480)">
<text x="0" y="12" font-size="11" class="muted-text">2:34</text>
<rect x="40" y="5" width="360" height="6" rx="3" class="progress-bg"/>
<rect x="40" y="5" width="150" height="6" rx="3" class="progress-fill"/>
<circle cx="190" cy="8" r="8" fill="#3b82f6"/>
<text x="410" y="12" font-size="11" class="muted-text">5:48</text>
</g>
<!-- Right Controls -->
<g transform="translate(590, 475)">
<!-- Volume -->
<circle cx="0" cy="15" r="15" class="control-btn"/>
<text x="0" y="20" text-anchor="middle" font-size="12" class="main-text">🔊</text>
<!-- Fullscreen -->
<circle cx="45" cy="15" r="15" class="control-btn"/>
<text x="45" y="20" text-anchor="middle" font-size="12" class="main-text"></text>
<!-- Settings -->
<circle cx="90" cy="15" r="15" class="control-btn"/>
<text x="90" y="20" text-anchor="middle" font-size="12" class="main-text"></text>
</g>
<!-- Right Sidebar - Playlist -->
<rect x="695" y="50" width="165" height="470" class="sidebar-bg"/>
<rect x="695" y="50" width="165" height="470" rx="8" class="border"/>
<text x="710" y="75" font-size="14" font-weight="600" class="main-text">Playlist</text>
<text x="710" y="95" font-size="11" class="secondary-text">12 slides • 5:48 total</text>
<!-- Thumbnail List -->
<g transform="translate(705, 115)">
<!-- Thumbnail 1 -->
<g transform="translate(0, 0)">
<rect x="0" y="0" width="145" height="55" rx="6" class="thumbnail"/>
<rect x="5" y="5" width="45" height="45" rx="4" fill="#334155"/>
<text x="27" y="33" text-anchor="middle" font-size="16" class="muted-text">1</text>
<text x="58" y="20" font-size="11" class="main-text">Title Slide</text>
<text x="58" y="35" font-size="10" class="muted-text">0:00</text>
</g>
<!-- Thumbnail 2 -->
<g transform="translate(0, 65)">
<rect x="0" y="0" width="145" height="55" rx="6" class="thumbnail"/>
<rect x="5" y="5" width="45" height="45" rx="4" fill="#334155"/>
<text x="27" y="33" text-anchor="middle" font-size="16" class="muted-text">2</text>
<text x="58" y="20" font-size="11" class="main-text">Agenda</text>
<text x="58" y="35" font-size="10" class="muted-text">0:30</text>
</g>
<!-- Thumbnail 3 -->
<g transform="translate(0, 130)">
<rect x="0" y="0" width="145" height="55" rx="6" class="thumbnail"/>
<rect x="5" y="5" width="45" height="45" rx="4" fill="#334155"/>
<text x="27" y="33" text-anchor="middle" font-size="16" class="muted-text">3</text>
<text x="58" y="20" font-size="11" class="main-text">Overview</text>
<text x="58" y="35" font-size="10" class="muted-text">1:15</text>
</g>
<!-- Thumbnail 4 -->
<g transform="translate(0, 195)">
<rect x="0" y="0" width="145" height="55" rx="6" class="thumbnail"/>
<rect x="5" y="5" width="45" height="45" rx="4" fill="#334155"/>
<text x="27" y="33" text-anchor="middle" font-size="16" class="muted-text">4</text>
<text x="58" y="20" font-size="11" class="main-text">Metrics</text>
<text x="58" y="35" font-size="10" class="muted-text">1:58</text>
</g>
<!-- Thumbnail 5 - Active -->
<g transform="translate(0, 260)">
<rect x="0" y="0" width="145" height="55" rx="6" class="thumbnail-active"/>
<rect x="5" y="5" width="45" height="45" rx="4" fill="#3b82f6"/>
<text x="27" y="33" text-anchor="middle" font-size="16" class="white-text">5</text>
<text x="58" y="20" font-size="11" class="accent-text">Q4 Review</text>
<text x="58" y="35" font-size="10" class="accent-text">▶ Playing</text>
</g>
<!-- Thumbnail 6 -->
<g transform="translate(0, 325)">
<rect x="0" y="0" width="145" height="55" rx="6" class="thumbnail"/>
<rect x="5" y="5" width="45" height="45" rx="4" fill="#334155"/>
<text x="27" y="33" text-anchor="middle" font-size="16" class="muted-text">6</text>
<text x="58" y="20" font-size="11" class="main-text">Roadmap</text>
<text x="58" y="35" font-size="10" class="muted-text">3:20</text>
</g>
<!-- More indicator -->
<text x="72" y="400" text-anchor="middle" font-size="11" class="muted-text">+ 6 more slides</text>
</g>
<!-- Footer -->
<g transform="translate(50, 555)">
<text x="0" y="0" font-size="10" class="muted-text">Space = Play/Pause | ← → = Navigate | F = Fullscreen | M = Mute</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.3 KiB

View file

@ -0,0 +1,160 @@
<svg width="900" height="600" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="accentGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#3b82f6"/>
<stop offset="100%" stop-color="#60a5fa"/>
</linearGradient>
</defs>
<style>
.bg { fill: #ffffff; }
.sidebar-bg { fill: #f8fafc; }
.main-text { fill: #1e293b; font-family: system-ui, -apple-system, sans-serif; }
.secondary-text { fill: #64748b; font-family: system-ui, -apple-system, sans-serif; }
.muted-text { fill: #94a3b8; font-family: system-ui, -apple-system, sans-serif; }
.white-text { fill: #ffffff; font-family: system-ui, -apple-system, sans-serif; }
.accent-text { fill: #3b82f6; font-family: system-ui, -apple-system, sans-serif; }
.border { stroke: #e2e8f0; stroke-width: 1; fill: none; }
.icon-btn { fill: #f1f5f9; }
.result-card { fill: #f8fafc; stroke: #e2e8f0; stroke-width: 1; }
.source-tag { fill: #dbeafe; }
.ai-response { fill: #eff6ff; stroke: #3b82f6; stroke-width: 1; }
@media (prefers-color-scheme: dark) {
.bg { fill: #0f172a; }
.sidebar-bg { fill: #1e293b; }
.main-text { fill: #e2e8f0; }
.secondary-text { fill: #94a3b8; }
.muted-text { fill: #64748b; }
.accent-text { fill: #60a5fa; }
.border { stroke: #334155; }
.icon-btn { fill: #334155; }
.result-card { fill: #1e293b; stroke: #334155; }
.source-tag { fill: #1e3a5f; }
.ai-response { fill: #1e3a5f; stroke: #3b82f6; }
}
</style>
<text x="450" y="25" text-anchor="middle" font-size="16" font-weight="600" class="main-text">Research - AI-Powered Search</text>
<rect x="30" y="40" width="840" height="530" rx="8" class="bg"/>
<rect x="30" y="40" width="840" height="530" rx="8" class="border"/>
<!-- Search Header -->
<g transform="translate(50, 60)">
<rect x="0" y="0" width="700" height="50" rx="25" class="icon-btn"/>
<rect x="0" y="0" width="700" height="50" rx="25" class="border"/>
<text x="25" y="32" font-size="16">🔍</text>
<text x="55" y="32" font-size="15" class="main-text">How does machine learning work in recommendation systems?</text>
<rect x="620" y="8" width="70" height="34" rx="17" fill="url(#accentGrad)"/>
<text x="655" y="30" text-anchor="middle" font-size="13" class="white-text">Search</text>
</g>
<!-- Filter Pills -->
<g transform="translate(50, 125)">
<rect x="0" y="0" width="60" height="28" rx="14" fill="url(#accentGrad)"/>
<text x="30" y="19" text-anchor="middle" font-size="11" class="white-text">All</text>
<rect x="70" y="0" width="70" height="28" rx="14" class="icon-btn"/>
<text x="105" y="19" text-anchor="middle" font-size="11" class="secondary-text">Articles</text>
<rect x="150" y="0" width="65" height="28" rx="14" class="icon-btn"/>
<text x="182" y="19" text-anchor="middle" font-size="11" class="secondary-text">Papers</text>
<rect x="225" y="0" width="55" height="28" rx="14" class="icon-btn"/>
<text x="252" y="19" text-anchor="middle" font-size="11" class="secondary-text">Web</text>
<rect x="290" y="0" width="65" height="28" rx="14" class="icon-btn"/>
<text x="322" y="19" text-anchor="middle" font-size="11" class="secondary-text">Videos</text>
<text x="600" y="19" font-size="12" class="muted-text">23 results • 1.2s</text>
</g>
<!-- AI Summary -->
<g transform="translate(50, 170)">
<rect x="0" y="0" width="600" height="140" rx="12" class="ai-response"/>
<text x="20" y="25" font-size="13" font-weight="600" class="accent-text">✨ AI Summary</text>
<text x="20" y="50" font-size="13" class="main-text">Machine learning powers recommendation systems through several key techniques:</text>
<text x="20" y="75" font-size="13" class="main-text">• Collaborative filtering analyzes user behavior patterns to find similar users</text>
<text x="20" y="95" font-size="13" class="main-text">• Content-based filtering matches item attributes to user preferences</text>
<text x="20" y="115" font-size="13" class="main-text">• Deep learning models can capture complex non-linear relationships</text>
<text x="20" y="135" font-size="11" class="muted-text">Based on 5 sources</text>
</g>
<!-- Search Results -->
<g transform="translate(50, 325)">
<!-- Result 1 -->
<rect x="0" y="0" width="600" height="90" rx="8" class="result-card"/>
<text x="15" y="25" font-size="14" font-weight="600" class="accent-text">Understanding Recommendation Systems: A Complete Guide</text>
<text x="15" y="45" font-size="12" class="secondary-text">ml-guide.com • Published 2024</text>
<text x="15" y="68" font-size="13" class="main-text">A comprehensive overview of how modern recommendation systems</text>
<text x="15" y="85" font-size="13" class="main-text">leverage machine learning algorithms to personalize content...</text>
<rect x="520" y="60" width="65" height="22" rx="11" class="source-tag"/>
<text x="552" y="75" text-anchor="middle" font-size="10" class="accent-text">Article</text>
</g>
<g transform="translate(50, 425)">
<!-- Result 2 -->
<rect x="0" y="0" width="600" height="90" rx="8" class="result-card"/>
<text x="15" y="25" font-size="14" font-weight="600" class="accent-text">Collaborative Filtering vs Content-Based: A Comparison</text>
<text x="15" y="45" font-size="12" class="secondary-text">research.ai • IEEE 2023</text>
<text x="15" y="68" font-size="13" class="main-text">This paper compares the effectiveness of collaborative filtering and</text>
<text x="15" y="85" font-size="13" class="main-text">content-based approaches in various recommendation scenarios...</text>
<rect x="520" y="60" width="65" height="22" rx="11" class="source-tag"/>
<text x="552" y="75" text-anchor="middle" font-size="10" class="accent-text">Paper</text>
</g>
<!-- Sources Panel -->
<rect x="670" y="170" width="185" height="345" rx="8" class="sidebar-bg"/>
<rect x="670" y="170" width="185" height="345" rx="8" class="border"/>
<text x="685" y="195" font-size="13" font-weight="600" class="main-text">Sources (5)</text>
<g transform="translate(685, 215)">
<rect x="0" y="0" width="155" height="55" rx="6" class="icon-btn"/>
<text x="10" y="20" font-size="11" font-weight="500" class="main-text">ML Guide</text>
<text x="10" y="38" font-size="10" class="muted-text">ml-guide.com</text>
<circle cx="140" cy="27" r="8" fill="#22c55e"/>
<text x="140" y="31" text-anchor="middle" font-size="8" class="white-text"></text>
</g>
<g transform="translate(685, 280)">
<rect x="0" y="0" width="155" height="55" rx="6" class="icon-btn"/>
<text x="10" y="20" font-size="11" font-weight="500" class="main-text">IEEE Research</text>
<text x="10" y="38" font-size="10" class="muted-text">ieee.org</text>
<circle cx="140" cy="27" r="8" fill="#22c55e"/>
<text x="140" y="31" text-anchor="middle" font-size="8" class="white-text"></text>
</g>
<g transform="translate(685, 345)">
<rect x="0" y="0" width="155" height="55" rx="6" class="icon-btn"/>
<text x="10" y="20" font-size="11" font-weight="500" class="main-text">ArXiv Paper</text>
<text x="10" y="38" font-size="10" class="muted-text">arxiv.org</text>
<circle cx="140" cy="27" r="8" fill="#22c55e"/>
<text x="140" y="31" text-anchor="middle" font-size="8" class="white-text"></text>
</g>
<g transform="translate(685, 410)">
<rect x="0" y="0" width="155" height="55" rx="6" class="icon-btn"/>
<text x="10" y="20" font-size="11" font-weight="500" class="main-text">Medium Article</text>
<text x="10" y="38" font-size="10" class="muted-text">medium.com</text>
<circle cx="140" cy="27" r="8" fill="#22c55e"/>
<text x="140" y="31" text-anchor="middle" font-size="8" class="white-text"></text>
</g>
<g transform="translate(685, 475)">
<rect x="0" y="0" width="155" height="30" rx="6" fill="url(#accentGrad)"/>
<text x="77" y="20" text-anchor="middle" font-size="11" class="white-text">+ Add Source</text>
</g>
<!-- Footer -->
<g transform="translate(50, 555)">
<text x="0" y="0" font-size="10" class="muted-text">Enter = Search | Tab = Next result | S = Save | E = Export citations</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.2 KiB

View file

@ -0,0 +1,248 @@
<svg width="900" height="600" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="accentGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#3b82f6"/>
<stop offset="100%" stop-color="#60a5fa"/>
</linearGradient>
<linearGradient id="purpleGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#8b5cf6"/>
<stop offset="100%" stop-color="#a78bfa"/>
</linearGradient>
<linearGradient id="greenGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#22c55e"/>
<stop offset="100%" stop-color="#4ade80"/>
</linearGradient>
<linearGradient id="orangeGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#f97316"/>
<stop offset="100%" stop-color="#fb923c"/>
</linearGradient>
</defs>
<style>
.bg { fill: #ffffff; }
.sidebar-bg { fill: #f8fafc; }
.main-text { fill: #1e293b; font-family: system-ui, -apple-system, sans-serif; }
.secondary-text { fill: #64748b; font-family: system-ui, -apple-system, sans-serif; }
.muted-text { fill: #94a3b8; font-family: system-ui, -apple-system, sans-serif; }
.white-text { fill: #ffffff; font-family: system-ui, -apple-system, sans-serif; }
.accent-text { fill: #3b82f6; font-family: system-ui, -apple-system, sans-serif; }
.border { stroke: #e2e8f0; stroke-width: 1; fill: none; }
.icon-btn { fill: #f1f5f9; }
.card { fill: #ffffff; stroke: #e2e8f0; stroke-width: 1; }
.card-hover { fill: #f8fafc; stroke: #3b82f6; stroke-width: 2; }
.tag { fill: #dbeafe; }
.tag-green { fill: #dcfce7; }
.tag-purple { fill: #f3e8ff; }
.tag-orange { fill: #ffedd5; }
@media (prefers-color-scheme: dark) {
.bg { fill: #0f172a; }
.sidebar-bg { fill: #1e293b; }
.main-text { fill: #e2e8f0; }
.secondary-text { fill: #94a3b8; }
.muted-text { fill: #64748b; }
.accent-text { fill: #60a5fa; }
.border { stroke: #334155; }
.icon-btn { fill: #334155; }
.card { fill: #1e293b; stroke: #334155; }
.card-hover { fill: #1e293b; stroke: #3b82f6; }
.tag { fill: #1e3a5f; }
.tag-green { fill: #14532d; }
.tag-purple { fill: #3b0764; }
.tag-orange { fill: #431407; }
}
</style>
<text x="450" y="25" text-anchor="middle" font-size="16" font-weight="600" class="main-text">Sources - Prompts &amp; Templates</text>
<rect x="30" y="40" width="840" height="530" rx="8" class="bg"/>
<rect x="30" y="40" width="840" height="530" rx="8" class="border"/>
<!-- Sidebar -->
<rect x="30" y="40" width="180" height="530" class="sidebar-bg"/>
<line x1="210" y1="40" x2="210" y2="570" class="border"/>
<!-- New Source Button -->
<g transform="translate(45, 55)">
<rect x="0" y="0" width="150" height="40" rx="8" fill="url(#accentGrad)"/>
<text x="75" y="26" text-anchor="middle" font-size="14" font-weight="500" class="white-text">+ New Source</text>
</g>
<!-- Categories -->
<g transform="translate(45, 115)">
<text x="0" y="0" font-size="11" font-weight="600" class="muted-text">CATEGORIES</text>
<g transform="translate(0, 20)">
<rect x="-10" y="-8" width="160" height="36" rx="6" fill="#eff6ff"/>
<text x="0" y="14" font-size="14">📚</text>
<text x="25" y="14" font-size="13" class="accent-text">All Sources</text>
<text x="130" y="14" font-size="12" class="accent-text">24</text>
</g>
<g transform="translate(0, 60)">
<text x="0" y="14" font-size="14">💬</text>
<text x="25" y="14" font-size="13" class="secondary-text">Prompts</text>
<text x="130" y="14" font-size="12" class="muted-text">12</text>
</g>
<g transform="translate(0, 95)">
<text x="0" y="14" font-size="14">📄</text>
<text x="25" y="14" font-size="13" class="secondary-text">Templates</text>
<text x="130" y="14" font-size="12" class="muted-text">8</text>
</g>
<g transform="translate(0, 130)">
<text x="0" y="14" font-size="14">🔗</text>
<text x="25" y="14" font-size="13" class="secondary-text">Integrations</text>
<text x="130" y="14" font-size="12" class="muted-text">4</text>
</g>
<g transform="translate(0, 165)">
<text x="0" y="14" font-size="14"></text>
<text x="25" y="14" font-size="13" class="secondary-text">Favorites</text>
<text x="130" y="14" font-size="12" class="muted-text">6</text>
</g>
</g>
<!-- Tags Section -->
<g transform="translate(45, 330)">
<text x="0" y="0" font-size="11" font-weight="600" class="muted-text">TAGS</text>
<g transform="translate(0, 18)">
<rect x="0" y="0" width="70" height="24" rx="12" class="tag"/>
<text x="35" y="16" text-anchor="middle" font-size="11" class="accent-text">customer</text>
</g>
<g transform="translate(78, 18)">
<rect x="0" y="0" width="55" height="24" rx="12" class="tag-green"/>
<text x="27" y="16" text-anchor="middle" font-size="11" fill="#16a34a">sales</text>
</g>
<g transform="translate(0, 50)">
<rect x="0" y="0" width="60" height="24" rx="12" class="tag-purple"/>
<text x="30" y="16" text-anchor="middle" font-size="11" fill="#7c3aed">support</text>
</g>
<g transform="translate(68, 50)">
<rect x="0" y="0" width="65" height="24" rx="12" class="tag-orange"/>
<text x="32" y="16" text-anchor="middle" font-size="11" fill="#c2410c">technical</text>
</g>
</g>
<!-- Main Content Header -->
<g transform="translate(230, 55)">
<text x="0" y="20" font-size="18" font-weight="600" class="main-text">All Sources</text>
<text x="0" y="42" font-size="13" class="secondary-text">24 items • Manage your prompts and templates</text>
<!-- Search and Filter -->
<g transform="translate(380, 5)">
<rect x="0" y="0" width="200" height="36" rx="18" class="icon-btn"/>
<rect x="0" y="0" width="200" height="36" rx="18" class="border"/>
<text x="20" y="23" font-size="14">🔍</text>
<text x="45" y="24" font-size="13" class="muted-text">Search sources...</text>
</g>
</g>
<!-- Cards Grid -->
<!-- Row 1 -->
<g transform="translate(230, 100)">
<!-- Card 1 - Selected -->
<rect x="0" y="0" width="185" height="140" rx="10" class="card-hover"/>
<rect x="15" y="15" width="40" height="40" rx="10" fill="url(#accentGrad)"/>
<text x="35" y="42" text-anchor="middle" font-size="20" class="white-text">💬</text>
<text x="15" y="75" font-size="14" font-weight="600" class="main-text">Customer Support</text>
<text x="15" y="95" font-size="12" class="secondary-text">Handle support inquiries</text>
<text x="15" y="110" font-size="12" class="secondary-text">with empathy and clarity</text>
<rect x="15" y="120" width="55" height="18" rx="9" class="tag"/>
<text x="42" y="132" text-anchor="middle" font-size="10" class="accent-text">prompt</text>
<!-- Card 2 -->
<rect x="200" y="0" width="185" height="140" rx="10" class="card"/>
<rect x="215" y="15" width="40" height="40" rx="10" fill="url(#purpleGrad)"/>
<text x="235" y="42" text-anchor="middle" font-size="20" class="white-text">📝</text>
<text x="215" y="75" font-size="14" font-weight="600" class="main-text">Email Template</text>
<text x="215" y="95" font-size="12" class="secondary-text">Professional email</text>
<text x="215" y="110" font-size="12" class="secondary-text">response format</text>
<rect x="215" y="120" width="60" height="18" rx="9" class="tag-purple"/>
<text x="245" y="132" text-anchor="middle" font-size="10" fill="#7c3aed">template</text>
<!-- Card 3 -->
<rect x="400" y="0" width="185" height="140" rx="10" class="card"/>
<rect x="415" y="15" width="40" height="40" rx="10" fill="url(#greenGrad)"/>
<text x="435" y="42" text-anchor="middle" font-size="20" class="white-text">🤖</text>
<text x="415" y="75" font-size="14" font-weight="600" class="main-text">Sales Assistant</text>
<text x="415" y="95" font-size="12" class="secondary-text">Product recommendations</text>
<text x="415" y="110" font-size="12" class="secondary-text">and pricing help</text>
<rect x="415" y="120" width="55" height="18" rx="9" class="tag"/>
<text x="442" y="132" text-anchor="middle" font-size="10" class="accent-text">prompt</text>
</g>
<!-- Row 2 -->
<g transform="translate(230, 255)">
<!-- Card 4 -->
<rect x="0" y="0" width="185" height="140" rx="10" class="card"/>
<rect x="15" y="15" width="40" height="40" rx="10" fill="url(#orangeGrad)"/>
<text x="35" y="42" text-anchor="middle" font-size="20" class="white-text">📊</text>
<text x="15" y="75" font-size="14" font-weight="600" class="main-text">Report Generator</text>
<text x="15" y="95" font-size="12" class="secondary-text">Create structured</text>
<text x="15" y="110" font-size="12" class="secondary-text">analysis reports</text>
<rect x="15" y="120" width="60" height="18" rx="9" class="tag-purple"/>
<text x="45" y="132" text-anchor="middle" font-size="10" fill="#7c3aed">template</text>
<!-- Card 5 -->
<rect x="200" y="0" width="185" height="140" rx="10" class="card"/>
<rect x="215" y="15" width="40" height="40" rx="10" fill="#ef4444"/>
<text x="235" y="42" text-anchor="middle" font-size="20" class="white-text">🔗</text>
<text x="215" y="75" font-size="14" font-weight="600" class="main-text">CRM Integration</text>
<text x="215" y="95" font-size="12" class="secondary-text">Connect with your</text>
<text x="215" y="110" font-size="12" class="secondary-text">CRM system</text>
<rect x="215" y="120" width="70" height="18" rx="9" class="tag-orange"/>
<text x="250" y="132" text-anchor="middle" font-size="10" fill="#c2410c">integration</text>
<!-- Card 6 -->
<rect x="400" y="0" width="185" height="140" rx="10" class="card"/>
<rect x="415" y="15" width="40" height="40" rx="10" fill="#06b6d4"/>
<text x="435" y="42" text-anchor="middle" font-size="20" class="white-text">🎯</text>
<text x="415" y="75" font-size="14" font-weight="600" class="main-text">FAQ Bot</text>
<text x="415" y="95" font-size="12" class="secondary-text">Automated answers</text>
<text x="415" y="110" font-size="12" class="secondary-text">for common questions</text>
<rect x="415" y="120" width="55" height="18" rx="9" class="tag"/>
<text x="442" y="132" text-anchor="middle" font-size="10" class="accent-text">prompt</text>
</g>
<!-- Row 3 -->
<g transform="translate(230, 410)">
<!-- Card 7 -->
<rect x="0" y="0" width="185" height="140" rx="10" class="card"/>
<rect x="15" y="15" width="40" height="40" rx="10" fill="#ec4899"/>
<text x="35" y="42" text-anchor="middle" font-size="20" class="white-text">✍️</text>
<text x="15" y="75" font-size="14" font-weight="600" class="main-text">Content Writer</text>
<text x="15" y="95" font-size="12" class="secondary-text">Blog posts and</text>
<text x="15" y="110" font-size="12" class="secondary-text">marketing copy</text>
<rect x="15" y="120" width="55" height="18" rx="9" class="tag"/>
<text x="42" y="132" text-anchor="middle" font-size="10" class="accent-text">prompt</text>
<!-- Card 8 -->
<rect x="200" y="0" width="185" height="140" rx="10" class="card"/>
<rect x="215" y="15" width="40" height="40" rx="10" fill="#14b8a6"/>
<text x="235" y="42" text-anchor="middle" font-size="20" class="white-text">📋</text>
<text x="215" y="75" font-size="14" font-weight="600" class="main-text">Meeting Notes</text>
<text x="215" y="95" font-size="12" class="secondary-text">Structured meeting</text>
<text x="215" y="110" font-size="12" class="secondary-text">summary template</text>
<rect x="215" y="120" width="60" height="18" rx="9" class="tag-purple"/>
<text x="245" y="132" text-anchor="middle" font-size="10" fill="#7c3aed">template</text>
<!-- Add New Card -->
<rect x="400" y="0" width="185" height="140" rx="10" class="icon-btn" stroke-dasharray="6,4"/>
<rect x="400" y="0" width="185" height="140" rx="10" class="border" stroke-dasharray="6,4"/>
<circle cx="492" cy="50" r="20" class="icon-btn"/>
<text x="492" y="58" text-anchor="middle" font-size="24" class="secondary-text">+</text>
<text x="492" y="90" text-anchor="middle" font-size="13" class="secondary-text">Add New Source</text>
<text x="492" y="110" text-anchor="middle" font-size="11" class="muted-text">Create from scratch</text>
</g>
<!-- Footer -->
<g transform="translate(230, 565)">
<text x="0" y="0" font-size="10" class="muted-text">Click to edit | Del = Delete | D = Duplicate | Enter = Use in chat</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -0,0 +1,220 @@
<svg width="900" height="600" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="accentGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#3b82f6"/>
<stop offset="100%" style="stop-color:#60a5fa"/>
</linearGradient>
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
<feDropShadow dx="0" dy="4" stdDeviation="8" flood-opacity="0.1"/>
</filter>
<filter id="shadowSm" x="-10%" y="-10%" width="120%" height="120%">
<feDropShadow dx="0" dy="2" stdDeviation="4" flood-opacity="0.08"/>
</filter>
</defs>
<style>
.bg { fill: #ffffff; }
.header-bg { fill: rgba(255,255,255,0.8); }
.main-text { fill: #1e293b; font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; }
.secondary-text { fill: #64748b; font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; }
.muted-text { fill: #94a3b8; font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; }
.accent-text { fill: #3b82f6; font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; }
.white-text { fill: #ffffff; font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; }
.card-bg { fill: #f8fafc; }
.border { stroke: #e2e8f0; stroke-width: 1; fill: none; }
.icon-btn { fill: #f1f5f9; }
.icon-btn:hover { fill: #e2e8f0; }
.user-bubble { fill: #3b82f6; }
.bot-bubble { fill: #f8fafc; stroke: #e2e8f0; stroke-width: 1; }
.input-bg { fill: #f1f5f9; }
.suggestion { fill: #eff6ff; stroke: #3b82f6; stroke-width: 1; }
.apps-grid-bg { fill: #ffffff; }
.app-item-hover { fill: #f1f5f9; }
.online-dot { fill: #22c55e; }
@media (prefers-color-scheme: dark) {
.bg { fill: #0f172a; }
.header-bg { fill: rgba(15,23,42,0.8); }
.main-text { fill: #e2e8f0; }
.secondary-text { fill: #94a3b8; }
.muted-text { fill: #64748b; }
.accent-text { fill: #60a5fa; }
.card-bg { fill: #1e293b; }
.border { stroke: #334155; }
.icon-btn { fill: #1e293b; }
.user-bubble { fill: #3b82f6; }
.bot-bubble { fill: #1e293b; stroke: #334155; }
.input-bg { fill: #1e293b; }
.suggestion { fill: #1e3a5f; stroke: #3b82f6; }
.apps-grid-bg { fill: #1e293b; }
.app-item-hover { fill: #334155; }
}
</style>
<!-- Title -->
<text x="450" y="25" text-anchor="middle" font-size="16" font-weight="600" class="main-text">Suite - Main Interface</text>
<!-- Background -->
<rect x="30" y="40" width="840" height="530" rx="12" class="bg" filter="url(#shadow)"/>
<!-- Floating Header (Glass morphism) -->
<rect x="50" y="55" width="800" height="56" rx="12" class="header-bg" filter="url(#shadowSm)"/>
<rect x="50" y="55" width="800" height="56" rx="12" class="border"/>
<!-- Logo -->
<rect x="70" y="70" width="28" height="28" rx="8" fill="url(#accentGrad)"/>
<text x="84" y="89" text-anchor="middle" font-size="14" class="white-text">GB</text>
<text x="110" y="90" font-size="15" font-weight="600" class="main-text">General Bots</text>
<!-- Header Right: Theme, Apps Grid, Avatar -->
<g transform="translate(650, 68)">
<!-- Theme dropdown -->
<rect x="0" y="0" width="70" height="32" rx="8" class="icon-btn"/>
<text x="15" y="21" font-size="12">☀️</text>
<text x="32" y="22" font-size="12" class="secondary-text">Light</text>
<!-- Apps grid button -->
<rect x="80" y="0" width="40" height="32" rx="8" class="icon-btn"/>
<g transform="translate(91, 8)">
<circle cx="4" cy="4" r="2.5" class="secondary-text" fill="#64748b"/>
<circle cx="13" cy="4" r="2.5" class="secondary-text" fill="#64748b"/>
<circle cx="4" cy="13" r="2.5" class="secondary-text" fill="#64748b"/>
<circle cx="13" cy="13" r="2.5" class="secondary-text" fill="#64748b"/>
</g>
<!-- User avatar -->
<circle cx="155" cy="16" r="16" fill="url(#accentGrad)"/>
<text x="155" y="21" text-anchor="middle" font-size="11" font-weight="500" class="white-text">JD</text>
</g>
<!-- Apps Dropdown (shown expanded) -->
<rect x="580" y="120" width="260" height="280" rx="12" class="apps-grid-bg" filter="url(#shadow)"/>
<rect x="580" y="120" width="260" height="280" rx="12" class="border"/>
<text x="600" y="148" font-size="13" font-weight="600" class="main-text">Applications</text>
<!-- App Grid Items -->
<g transform="translate(595, 160)">
<!-- Row 1 -->
<g transform="translate(0, 0)">
<rect x="0" y="0" width="70" height="65" rx="8" class="app-item-hover"/>
<rect x="20" y="10" width="30" height="30" rx="8" fill="#3b82f6"/>
<text x="35" y="30" text-anchor="middle" font-size="14" class="white-text">💬</text>
<text x="35" y="55" text-anchor="middle" font-size="11" class="main-text">Chat</text>
</g>
<g transform="translate(75, 0)">
<rect x="0" y="0" width="70" height="65" rx="8" fill="none"/>
<rect x="20" y="10" width="30" height="30" rx="8" fill="#f59e0b"/>
<text x="35" y="30" text-anchor="middle" font-size="14" class="white-text">📁</text>
<text x="35" y="55" text-anchor="middle" font-size="11" class="main-text">Drive</text>
</g>
<g transform="translate(150, 0)">
<rect x="0" y="0" width="70" height="65" rx="8" fill="none"/>
<rect x="20" y="10" width="30" height="30" rx="8" fill="#10b981"/>
<text x="35" y="30" text-anchor="middle" font-size="14" class="white-text"></text>
<text x="35" y="55" text-anchor="middle" font-size="11" class="main-text">Tasks</text>
</g>
<!-- Row 2 -->
<g transform="translate(0, 70)">
<rect x="0" y="0" width="70" height="65" rx="8" fill="none"/>
<rect x="20" y="10" width="30" height="30" rx="8" fill="#ef4444"/>
<text x="35" y="30" text-anchor="middle" font-size="14" class="white-text"></text>
<text x="35" y="55" text-anchor="middle" font-size="11" class="main-text">Mail</text>
</g>
<g transform="translate(75, 70)">
<rect x="0" y="0" width="70" height="65" rx="8" fill="none"/>
<rect x="20" y="10" width="30" height="30" rx="8" fill="#8b5cf6"/>
<text x="35" y="30" text-anchor="middle" font-size="14" class="white-text">📅</text>
<text x="35" y="55" text-anchor="middle" font-size="11" class="main-text">Calendar</text>
</g>
<g transform="translate(150, 70)">
<rect x="0" y="0" width="70" height="65" rx="8" fill="none"/>
<rect x="20" y="10" width="30" height="30" rx="8" fill="#06b6d4"/>
<text x="35" y="30" text-anchor="middle" font-size="14" class="white-text">🎥</text>
<text x="35" y="55" text-anchor="middle" font-size="11" class="main-text">Meet</text>
</g>
<!-- Row 3 -->
<g transform="translate(0, 140)">
<rect x="0" y="0" width="70" height="65" rx="8" fill="none"/>
<rect x="20" y="10" width="30" height="30" rx="8" fill="#ec4899"/>
<text x="35" y="30" text-anchor="middle" font-size="14" class="white-text">📝</text>
<text x="35" y="55" text-anchor="middle" font-size="11" class="main-text">Paper</text>
</g>
<g transform="translate(75, 140)">
<rect x="0" y="0" width="70" height="65" rx="8" fill="none"/>
<rect x="20" y="10" width="30" height="30" rx="8" fill="#14b8a6"/>
<text x="35" y="30" text-anchor="middle" font-size="14" class="white-text">🔍</text>
<text x="35" y="55" text-anchor="middle" font-size="11" class="main-text">Research</text>
</g>
<g transform="translate(150, 140)">
<rect x="0" y="0" width="70" height="65" rx="8" fill="none"/>
<rect x="20" y="10" width="30" height="30" rx="8" fill="#f97316"/>
<text x="35" y="30" text-anchor="middle" font-size="14" class="white-text">📊</text>
<text x="35" y="55" text-anchor="middle" font-size="11" class="main-text">Analytics</text>
</g>
</g>
<!-- Main Content Area (Chat shown as default) -->
<rect x="50" y="125" width="510" height="430" rx="12" class="card-bg"/>
<rect x="50" y="125" width="510" height="430" rx="12" class="border"/>
<!-- Connection status -->
<g transform="translate(70, 140)">
<circle cx="5" cy="5" r="4" class="online-dot"/>
<text x="15" y="9" font-size="11" class="secondary-text">Connected</text>
</g>
<!-- Chat Messages -->
<g transform="translate(70, 170)">
<!-- Bot message -->
<rect x="0" y="0" width="350" height="60" rx="12" class="bot-bubble"/>
<text x="15" y="22" font-size="11" class="accent-text">AI Assistant</text>
<text x="15" y="42" font-size="13" class="main-text">Hello! How can I help you today?</text>
<!-- User message -->
<rect x="140" y="75" width="330" height="40" rx="12" class="user-bubble"/>
<text x="155" y="100" font-size="13" class="white-text">What's on my calendar for today?</text>
<!-- Bot response -->
<rect x="0" y="130" width="380" height="90" rx="12" class="bot-bubble"/>
<text x="15" y="152" font-size="11" class="accent-text">AI Assistant</text>
<text x="15" y="175" font-size="13" class="main-text">You have 2 meetings today:</text>
<text x="15" y="195" font-size="12" class="secondary-text">• 2:00 PM - Team Standup</text>
<text x="15" y="212" font-size="12" class="secondary-text">• 4:00 PM - Project Review</text>
</g>
<!-- Suggestions -->
<g transform="translate(70, 430)">
<rect x="0" y="0" width="110" height="30" rx="15" class="suggestion"/>
<text x="55" y="20" text-anchor="middle" font-size="11" class="accent-text">📧 Check email</text>
<rect x="120" y="0" width="100" height="30" rx="15" class="suggestion"/>
<text x="170" y="20" text-anchor="middle" font-size="11" class="accent-text">✓ My tasks</text>
<rect x="230" y="0" width="120" height="30" rx="15" class="suggestion"/>
<text x="290" y="20" text-anchor="middle" font-size="11" class="accent-text">📁 Recent files</text>
</g>
<!-- Input Area -->
<g transform="translate(70, 475)">
<rect x="0" y="0" width="400" height="48" rx="24" class="input-bg"/>
<text x="20" y="30" font-size="13" class="muted-text">Message...</text>
<rect x="320" y="8" width="32" height="32" rx="16" class="icon-btn"/>
<text x="336" y="30" text-anchor="middle" font-size="14">🎤</text>
<rect x="360" y="8" width="32" height="32" rx="16" fill="url(#accentGrad)"/>
<text x="376" y="30" text-anchor="middle" font-size="14" class="white-text"></text>
</g>
<!-- Scroll to bottom button -->
<circle cx="520" cy="510" r="18" class="icon-btn" filter="url(#shadowSm)"/>
<text x="520" y="516" text-anchor="middle" font-size="16" class="secondary-text"></text>
<!-- Keyboard shortcuts legend -->
<g transform="translate(50, 565)">
<text x="0" y="0" font-size="10" class="muted-text">Enter = Send | Shift+Enter = New line | / = Commands | @ = Mention</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -0,0 +1,211 @@
<svg width="900" height="600" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="accentGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#3b82f6"/>
<stop offset="100%" stop-color="#60a5fa"/>
</linearGradient>
</defs>
<style>
.bg { fill: #ffffff; }
.sidebar-bg { fill: #f8fafc; }
.main-text { fill: #1e293b; font-family: system-ui, -apple-system, sans-serif; }
.secondary-text { fill: #64748b; font-family: system-ui, -apple-system, sans-serif; }
.muted-text { fill: #94a3b8; font-family: system-ui, -apple-system, sans-serif; }
.white-text { fill: #ffffff; font-family: system-ui, -apple-system, sans-serif; }
.accent-text { fill: #3b82f6; font-family: system-ui, -apple-system, sans-serif; }
.border { stroke: #e2e8f0; stroke-width: 1; fill: none; }
.icon-btn { fill: #f1f5f9; }
.checkbox { fill: #ffffff; stroke: #cbd5e1; stroke-width: 2; }
.checkbox-checked { fill: #22c55e; stroke: #22c55e; stroke-width: 2; }
.task-row { fill: #ffffff; }
.task-row-hover { fill: #f8fafc; }
.priority-high { fill: #ef4444; }
.priority-medium { fill: #f97316; }
.priority-low { fill: #22c55e; }
.nav-active { fill: #eff6ff; }
.tag-blue { fill: #dbeafe; }
.tag-green { fill: #dcfce7; }
.tag-purple { fill: #f3e8ff; }
@media (prefers-color-scheme: dark) {
.bg { fill: #0f172a; }
.sidebar-bg { fill: #1e293b; }
.main-text { fill: #e2e8f0; }
.secondary-text { fill: #94a3b8; }
.muted-text { fill: #64748b; }
.accent-text { fill: #60a5fa; }
.border { stroke: #334155; }
.icon-btn { fill: #334155; }
.checkbox { fill: #1e293b; stroke: #475569; }
.task-row { fill: #0f172a; }
.task-row-hover { fill: #1e293b; }
.nav-active { fill: #1e3a5f; }
.tag-blue { fill: #1e3a5f; }
.tag-green { fill: #14532d; }
.tag-purple { fill: #3b0764; }
}
</style>
<text x="450" y="25" text-anchor="middle" font-size="16" font-weight="600" class="main-text">Tasks - To-Do Manager</text>
<rect x="30" y="40" width="840" height="530" rx="8" class="bg"/>
<rect x="30" y="40" width="840" height="530" rx="8" class="border"/>
<!-- Sidebar -->
<rect x="30" y="40" width="180" height="530" class="sidebar-bg"/>
<line x1="210" y1="40" x2="210" y2="570" class="border"/>
<!-- Add Task Button -->
<g transform="translate(45, 55)">
<rect x="0" y="0" width="150" height="40" rx="8" fill="url(#accentGrad)"/>
<text x="75" y="26" text-anchor="middle" font-size="14" font-weight="500" class="white-text">+ Add Task</text>
</g>
<!-- Navigation -->
<g transform="translate(45, 115)">
<rect x="-10" y="-8" width="160" height="36" rx="6" class="nav-active"/>
<text x="0" y="14" font-size="14">📋</text>
<text x="25" y="14" font-size="14" class="accent-text">All Tasks</text>
<text x="130" y="14" font-size="12" class="accent-text">12</text>
<text x="0" y="54" font-size="14">📅</text>
<text x="25" y="54" font-size="14" class="secondary-text">Today</text>
<text x="130" y="54" font-size="12" class="secondary-text">5</text>
<text x="0" y="94" font-size="14">📆</text>
<text x="25" y="94" font-size="14" class="secondary-text">Upcoming</text>
<text x="130" y="94" font-size="12" class="secondary-text">8</text>
<text x="0" y="134" font-size="14"></text>
<text x="25" y="134" font-size="14" class="secondary-text">Important</text>
<text x="130" y="134" font-size="12" class="secondary-text">3</text>
<text x="0" y="174" font-size="14"></text>
<text x="25" y="174" font-size="14" class="secondary-text">Completed</text>
<text x="130" y="174" font-size="12" class="secondary-text">24</text>
</g>
<!-- Projects Section -->
<g transform="translate(45, 320)">
<text x="0" y="0" font-size="11" font-weight="600" class="muted-text">PROJECTS</text>
<g transform="translate(0, 20)">
<circle cx="7" cy="7" r="5" fill="#3b82f6"/>
<text x="20" y="11" font-size="13" class="main-text">Work</text>
</g>
<g transform="translate(0, 45)">
<circle cx="7" cy="7" r="5" fill="#22c55e"/>
<text x="20" y="11" font-size="13" class="main-text">Personal</text>
</g>
<g transform="translate(0, 70)">
<circle cx="7" cy="7" r="5" fill="#8b5cf6"/>
<text x="20" y="11" font-size="13" class="main-text">Learning</text>
</g>
</g>
<!-- Main Content Header -->
<g transform="translate(230, 55)">
<text x="0" y="20" font-size="18" font-weight="600" class="main-text">All Tasks</text>
<text x="0" y="40" font-size="13" class="secondary-text">12 tasks, 5 due today</text>
<!-- Filter/Sort -->
<g transform="translate(450, 5)">
<rect x="0" y="0" width="80" height="32" rx="6" class="icon-btn"/>
<text x="40" y="21" text-anchor="middle" font-size="12" class="secondary-text">Filter ▾</text>
<rect x="90" y="0" width="70" height="32" rx="6" class="icon-btn"/>
<text x="125" y="21" text-anchor="middle" font-size="12" class="secondary-text">Sort ▾</text>
</g>
</g>
<!-- Task Input -->
<g transform="translate(230, 100)">
<rect x="0" y="0" width="620" height="45" rx="8" class="icon-btn"/>
<rect x="0" y="0" width="620" height="45" rx="8" class="border"/>
<circle cx="25" cy="22" r="10" class="checkbox"/>
<text x="50" y="27" font-size="14" class="muted-text">Add a new task...</text>
</g>
<!-- Task List -->
<g transform="translate(230, 160)">
<!-- Task 1 - High Priority -->
<g transform="translate(0, 0)">
<rect x="0" y="0" width="620" height="55" rx="6" class="task-row-hover"/>
<circle cx="25" cy="27" r="10" class="checkbox"/>
<rect x="45" y="20" width="4" height="16" rx="2" class="priority-high"/>
<text x="60" y="25" font-size="14" font-weight="500" class="main-text">Complete quarterly report</text>
<rect x="60" y="32" width="45" height="18" rx="9" class="tag-blue"/>
<text x="82" y="44" text-anchor="middle" font-size="10" class="accent-text">Work</text>
<text x="500" y="30" font-size="12" class="priority-high">Today</text>
<text x="580" y="30" font-size="14" class="muted-text"></text>
</g>
<!-- Task 2 - High Priority -->
<g transform="translate(0, 60)">
<rect x="0" y="0" width="620" height="55" rx="6" class="task-row"/>
<circle cx="25" cy="27" r="10" class="checkbox"/>
<rect x="45" y="20" width="4" height="16" rx="2" class="priority-high"/>
<text x="60" y="25" font-size="14" font-weight="500" class="main-text">Review pull request #234</text>
<rect x="60" y="32" width="45" height="18" rx="9" class="tag-blue"/>
<text x="82" y="44" text-anchor="middle" font-size="10" class="accent-text">Work</text>
<text x="500" y="30" font-size="12" class="priority-high">Today</text>
<text x="580" y="30" font-size="14" class="secondary-text"></text>
</g>
<!-- Task 3 - Medium Priority -->
<g transform="translate(0, 120)">
<rect x="0" y="0" width="620" height="55" rx="6" class="task-row"/>
<circle cx="25" cy="27" r="10" class="checkbox"/>
<rect x="45" y="20" width="4" height="16" rx="2" class="priority-medium"/>
<text x="60" y="25" font-size="14" font-weight="500" class="main-text">Prepare presentation slides</text>
<rect x="60" y="32" width="45" height="18" rx="9" class="tag-blue"/>
<text x="82" y="44" text-anchor="middle" font-size="10" class="accent-text">Work</text>
<text x="500" y="30" font-size="12" class="secondary-text">Tomorrow</text>
<text x="580" y="30" font-size="14" class="secondary-text"></text>
</g>
<!-- Task 4 - Low Priority -->
<g transform="translate(0, 180)">
<rect x="0" y="0" width="620" height="55" rx="6" class="task-row"/>
<circle cx="25" cy="27" r="10" class="checkbox"/>
<rect x="45" y="20" width="4" height="16" rx="2" class="priority-low"/>
<text x="60" y="25" font-size="14" font-weight="500" class="main-text">Read documentation updates</text>
<rect x="60" y="32" width="55" height="18" rx="9" class="tag-purple"/>
<text x="87" y="44" text-anchor="middle" font-size="10" fill="#7c3aed">Learning</text>
<text x="500" y="30" font-size="12" class="secondary-text">Mar 20</text>
<text x="580" y="30" font-size="14" class="secondary-text"></text>
</g>
<!-- Task 5 - Completed -->
<g transform="translate(0, 240)">
<rect x="0" y="0" width="620" height="55" rx="6" class="task-row"/>
<circle cx="25" cy="27" r="10" class="checkbox-checked"/>
<text x="25" y="32" text-anchor="middle" font-size="12" class="white-text"></text>
<text x="60" y="25" font-size="14" class="muted-text" text-decoration="line-through">Update team meeting notes</text>
<rect x="60" y="32" width="45" height="18" rx="9" class="tag-blue"/>
<text x="82" y="44" text-anchor="middle" font-size="10" class="muted-text">Work</text>
<text x="500" y="30" font-size="12" class="muted-text">Completed</text>
<text x="580" y="30" font-size="14" class="muted-text"></text>
</g>
<!-- Task 6 - Completed -->
<g transform="translate(0, 300)">
<rect x="0" y="0" width="620" height="55" rx="6" class="task-row"/>
<circle cx="25" cy="27" r="10" class="checkbox-checked"/>
<text x="25" y="32" text-anchor="middle" font-size="12" class="white-text"></text>
<text x="60" y="25" font-size="14" class="muted-text" text-decoration="line-through">Schedule dentist appointment</text>
<rect x="60" y="32" width="55" height="18" rx="9" class="tag-green"/>
<text x="87" y="44" text-anchor="middle" font-size="10" fill="#16a34a">Personal</text>
<text x="500" y="30" font-size="12" class="muted-text">Completed</text>
<text x="580" y="30" font-size="14" class="muted-text"></text>
</g>
</g>
<!-- Footer -->
<g transform="translate(230, 555)">
<text x="0" y="0" font-size="10" class="muted-text">Enter = Add task | Space = Toggle complete | Del = Delete | S = Star</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.9 KiB

209
docs/src/assets/wa-chat.css Normal file
View file

@ -0,0 +1,209 @@
/**
* WhatsApp-style Chat Conversation CSS
*
* Standard styling for conversation examples in General Bots documentation.
* Include this CSS in your mdBook or HTML output to style <div class="wa-chat"> elements.
*
* Usage:
* <div class="wa-chat">
* <div class="wa-message bot">
* <div class="wa-bubble">
* <p>Bot message here</p>
* <div class="wa-time">10:30</div>
* </div>
* </div>
* <div class="wa-message user">
* <div class="wa-bubble">
* <p>User message here</p>
* <div class="wa-time">10:31</div>
* </div>
* </div>
* </div>
*/
/* ============================================
Chat Container
============================================ */
.wa-chat {
background-color: #e5ddd5;
border-radius: 8px;
padding: 20px 15px;
margin: 20px 0;
max-width: 500px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
font-size: 14px;
}
/* Dark mode support */
@media (prefers-color-scheme: dark) {
.wa-chat {
background-color: #0b141a;
}
}
/* ============================================
Message Container
============================================ */
.wa-message {
margin-bottom: 10px;
}
.wa-message:last-child {
margin-bottom: 0;
}
/* User messages align right */
.wa-message.user {
text-align: right;
}
/* ============================================
Message Bubbles
============================================ */
.wa-bubble {
padding: 8px 12px;
border-radius: 8px;
box-shadow: 0 1px 0.5px rgba(0, 0, 0, 0.13);
max-width: 85%;
display: inline-block;
text-align: left;
}
/* Bot bubble - white/light */
.wa-message.bot .wa-bubble {
background-color: #fff;
}
/* User bubble - green (WhatsApp style) */
.wa-message.user .wa-bubble {
background-color: #dcf8c6;
}
/* Dark mode bubbles */
@media (prefers-color-scheme: dark) {
.wa-message.bot .wa-bubble {
background-color: #202c33;
}
.wa-message.user .wa-bubble {
background-color: #005c4b;
}
}
/* ============================================
Message Text
============================================ */
.wa-bubble p {
margin: 0 0 4px 0;
line-height: 1.4;
color: #303030;
}
.wa-bubble p:last-of-type {
margin-bottom: 0;
}
/* Bold text in messages */
.wa-bubble strong {
font-weight: 600;
}
/* Dark mode text */
@media (prefers-color-scheme: dark) {
.wa-bubble p {
color: #e9edef;
}
}
/* ============================================
Timestamp
============================================ */
.wa-time {
font-size: 11px;
color: #8696a0;
text-align: right;
margin-top: 4px;
}
/* ============================================
Special Elements
============================================ */
/* Links in messages */
.wa-bubble a {
color: #00a884;
text-decoration: none;
}
.wa-bubble a:hover {
text-decoration: underline;
}
/* Code in messages */
.wa-bubble code {
background-color: rgba(0, 0, 0, 0.05);
padding: 2px 4px;
border-radius: 3px;
font-family: 'SF Mono', Consolas, 'Liberation Mono', Menlo, monospace;
font-size: 13px;
}
@media (prefers-color-scheme: dark) {
.wa-bubble code {
background-color: rgba(255, 255, 255, 0.1);
}
}
/* Action buttons in messages */
.wa-bubble .wa-action {
display: inline-block;
background-color: #e8f4fd;
color: #4a90e2;
padding: 4px 10px;
border-radius: 4px;
font-size: 12px;
margin: 4px 4px 0 0;
cursor: pointer;
}
.wa-bubble .wa-action:hover {
background-color: #d0e8fc;
}
@media (prefers-color-scheme: dark) {
.wa-bubble .wa-action {
background-color: #1a3a4a;
color: #00d4ff;
}
.wa-bubble .wa-action:hover {
background-color: #2a4a5a;
}
}
/* ============================================
Variants
============================================ */
/* Full-width variant */
.wa-chat.wa-full-width {
max-width: 100%;
}
/* Compact variant (less padding) */
.wa-chat.wa-compact {
padding: 12px 10px;
}
.wa-chat.wa-compact .wa-message {
margin-bottom: 6px;
}
.wa-chat.wa-compact .wa-bubble {
padding: 6px 10px;
}
/* No-time variant (hide timestamps) */
.wa-chat.wa-no-time .wa-time {
display: none;
}

View file

@ -2,7 +2,7 @@
> **Your business intelligence center**
<img src="../../assets/suite/analytics-flow.svg" alt="Analytics Flow Diagram" style="max-width: 100%; height: auto;">
<img src="../../assets/suite/analytics-screen.svg" alt="Analytics Interface Screen" style="max-width: 100%; height: auto;">
---

View file

@ -2,7 +2,7 @@
> **Your personal scheduling assistant**
![Calendar Flow](../../assets/suite/calendar-flow.svg)
<img src="../../assets/suite/calendar-screen.svg" alt="Calendar Interface Screen" style="max-width: 100%; height: auto;">
---

View file

@ -2,7 +2,7 @@
> **Your intelligent conversation partner**
<img src="../../assets/suite/chat-flow.svg" alt="Chat Flow Diagram" style="max-width: 100%; height: auto;">
<img src="../../assets/suite/chat-screen.svg" alt="Chat Interface Screen" style="max-width: 100%; height: auto;">
---

View file

@ -2,7 +2,7 @@
> **Your privacy and security guardian**
<img src="../../assets/suite/compliance-flow.svg" alt="Compliance Flow Diagram" style="max-width: 100%; height: auto;">
<img src="../../assets/suite/compliance-screen.svg" alt="Compliance Interface Screen" style="max-width: 100%; height: auto;">
---

View file

@ -2,7 +2,7 @@
> **Your no-code bot building studio**
<img src="../../assets/suite/designer-flow.svg" alt="Designer Flow Diagram" style="max-width: 100%; height: auto;">
<img src="../../assets/suite/designer-screen.svg" alt="Designer Interface Screen" style="max-width: 100%; height: auto;">
---

View file

@ -2,7 +2,7 @@
> **Your cloud storage workspace**
<img src="../../assets/suite/drive-flow.svg" alt="Drive Flow Diagram" style="max-width: 100%; height: auto;">
<img src="../../assets/suite/drive-screen.svg" alt="Drive Interface Screen" style="max-width: 100%; height: auto;">
---

View file

@ -2,7 +2,7 @@
> **Your intelligent inbox**
![Mail Flow](../../assets/suite/mail-flow.svg)
<img src="../../assets/suite/mail-screen.svg" alt="Mail Interface Screen" style="max-width: 100%; height: auto;">
---

View file

@ -2,7 +2,7 @@
> **Your virtual meeting room**
![Meet Flow](../../assets/suite/meet-flow.svg)
<img src="../../assets/suite/meet-screen.svg" alt="Meet Interface Screen" style="max-width: 100%; height: auto;">
---

View file

@ -2,7 +2,7 @@
> **Your intelligent document editor**
<img src="../../assets/suite/paper-flow.svg" alt="Paper Flow Diagram" style="max-width: 100%; height: auto;">
<img src="../../assets/suite/paper-screen.svg" alt="Paper Interface Screen" style="max-width: 100%; height: auto;">
---

View file

@ -2,7 +2,7 @@
> **Integrated viewing for documents, audio, video, and presentations**
<img src="../../assets/suite/player-flow.svg" alt="Player Flow" style="max-width: 100%; height: auto;">
<img src="../../assets/suite/player-screen.svg" alt="Player Interface Screen" style="max-width: 100%; height: auto;">
---

View file

@ -2,7 +2,7 @@
> **Your intelligent research assistant**
<img src="../../assets/suite/research-flow.svg" alt="Research Flow Diagram" style="max-width: 100%; height: auto;">
<img src="../../assets/suite/research-screen.svg" alt="Research Interface Screen" style="max-width: 100%; height: auto;">
---

View file

@ -2,7 +2,7 @@
> **Your bot configuration hub**
<img src="../../assets/suite/sources-flow.svg" alt="Sources Flow Diagram" style="max-width: 100%; height: auto;">
<img src="../../assets/suite/sources-screen.svg" alt="Sources Interface Screen" style="max-width: 100%; height: auto;">
---

View file

@ -2,7 +2,7 @@
> **Complete productivity suite with integrated applications**
<img src="../../assets/suite/suite-layout.svg" alt="Suite Layout" style="max-width: 100%; height: auto;">
<img src="../../assets/suite/suite-screen.svg" alt="Suite Interface Screen" style="max-width: 100%; height: auto;">
---

View file

@ -2,7 +2,7 @@
> **Track what needs to be done**
<img src="../../assets/suite/tasks-flow.svg" alt="Tasks Flow Diagram" style="max-width: 100%; height: auto;">
<img src="../../assets/suite/tasks-screen.svg" alt="Tasks Interface Screen" style="max-width: 100%; height: auto;">
---

View file

@ -30,18 +30,7 @@ General Bots Suite is your all-in-one workspace that combines communication, pro
When the Suite opens, you see:
```
┌─────────────────────────────────────────────────────────────────┐
│ 🤖 General Bots [Apps Menu ⋮⋮⋮] [Theme 🌙] [U] │
├─────────────────────────────────────────────────────────────────┤
│ │
│ │
│ 💬 Chat (Main Area) │
│ │
│ Type your message here... │
│ │
└─────────────────────────────────────────────────────────────────┘
```
<img src="../assets/chapter-04/suite-main-layout.svg" alt="Suite Main Layout" style="max-width: 100%; height: auto;">
### The Apps Menu
@ -136,22 +125,7 @@ Drive is your file storage - like Google Drive or OneDrive. Store documents, ima
### The Drive Interface
```
┌─────────────────────────────────────────────────────────────────┐
│ [+ New ▼] 🔍 Search files... [⊞] [≡] │
├──────────────┬──────────────────────────────────────────────────┤
│ │ 📁 My Drive > Projects > 2024 │
│ My Drive │ ─────────────────────────────────────────────────│
│ ⭐ Starred │ [☐] Name Size Modified │
│ 🕐 Recent │ ─────────────────────────────────────────────── │
│ 🗑 Trash │ 📁 Reports - Today │
│ │ 📁 Presentations - Yesterday │
│ ───────────│ 📄 Budget.xlsx 245 KB Mar 15 │
│ Labels │ 📄 Notes.docx 12 KB Mar 14 │
│ 🔵 Work │ 🖼 Logo.png 89 KB Mar 10 │
│ 🟢 Personal│ │
└──────────────┴──────────────────────────────────────────────────┘
```
<img src="../assets/chapter-04/drive-interface.svg" alt="Drive Interface" style="max-width: 100%; height: auto;">
### Creating and Uploading
@ -213,23 +187,7 @@ Tasks helps you track what needs to be done. Create to-do lists, set due dates,
### The Tasks Interface
```
┌─────────────────────────────────────────────────────────────────┐
│ ✓ Tasks Total: 12 Active: 5 Done: 7│
├─────────────────────────────────────────────────────────────────┤
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ What needs to be done? [Category ▼] [+ Add]│ │
│ └─────────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────────┤
│ [📋 All (12)] [⏳ Active (5)] [✓ Completed (7)] [⚡ Priority] │
├─────────────────────────────────────────────────────────────────┤
│ ☐ Review quarterly report 📅 Today 🔴 │
│ ☐ Call client about proposal 📅 Today 🟡 │
│ ☐ Update project documentation 📅 Tomorrow 🟢 │
│ ☑ Send meeting notes ✓ Done │
│ ☑ Complete expense report ✓ Done │
└─────────────────────────────────────────────────────────────────┘
```
<img src="../assets/chapter-04/tasks-interface.svg" alt="Tasks Interface" style="max-width: 100%; height: auto;">
### Adding a Task
@ -281,24 +239,7 @@ Mail connects to your email accounts so you can read, write, and organize emails
### The Mail Interface
```
┌────────────────┬───────────────────┬────────────────────────────┐
│ │ │ │
│ [✏ Compose] │ Inbox │ From: john@company.com │
│ │ │ Subject: Project Update │
│ 📥 Inbox (3) │ ● Project Update │ ──────────────────────── │
│ 📤 Sent │ from John │ │
│ 📝 Drafts │ 10:30 AM │ Hi, │
│ 🗑 Trash │ │ │
│ │ ○ Meeting Notes │ Here's the latest update │
│ │ from Sarah │ on our project... │
│ │ Yesterday │ │
│ │ │ Best, │
│ │ ○ Invoice #1234 │ John │
│ │ from Vendor │ │
│ │ Mar 15 │ [Reply] [Forward] [Delete]│
└────────────────┴───────────────────┴────────────────────────────┘
```
<img src="../assets/chapter-04/mail-interface.svg" alt="Mail Interface" style="max-width: 100%; height: auto;">
### Reading Email
@ -364,25 +305,7 @@ Calendar shows your schedule, meetings, and events. Plan your day, week, or mont
### The Calendar Interface
```
┌─────────────────────────────────────────────────────────────────┐
│ ◄ March 2024 ► [Day] [Week] [Month] │
├─────────────────────────────────────────────────────────────────┤
│ Mon Tue Wed Thu Fri Sat Sun │
│ ────────────────────────────────────────────────────────────── │
│ 1 2 3 │
│ │
│ 4 5 6 7 8 9 10 │
│ ████ │
│ Team │
│ Meeting │
│ │
│ 11 12 13 14 15 16 17 │
│ ████ ████ │
│ Project Review │
│ Demo 1:1 │
└─────────────────────────────────────────────────────────────────┘
```
<img src="../assets/chapter-04/calendar-interface.svg" alt="Calendar Interface" style="max-width: 100%; height: auto;">
### Creating an Event
@ -457,24 +380,7 @@ Bot: Meeting scheduled:
### The Meeting Interface
```
┌─────────────────────────────────────────────────────────────────┐
│ Meeting Room 00:15:32 [👥 3] [💬] │
├─────────────────────────────────────────────────────────────────┤
│ ┌─────────────────────┐ ┌─────────────────────┐ │
│ │ │ │ │ │
│ │ 👤 You │ │ 👤 John │ │
│ │ │ │ │ │
│ │ (Camera) │ │ (Camera) │ │
│ └─────────────────────┘ └─────────────────────┘ │
│ │
│ ┌─────────────────────┐ │
│ │ 👤 Sarah │ │
│ └─────────────────────┘ │
├─────────────────────────────────────────────────────────────────┤
│ [🎤 Mute] [📹 Video] [🖥 Share] [🔴 Record] [📞 End] │
└─────────────────────────────────────────────────────────────────┘
```
<img src="../assets/chapter-04/meet-interface.svg" alt="Meet Interface" style="max-width: 100%; height: auto;">
### Meeting Controls
@ -536,24 +442,7 @@ Paper is your writing space with AI assistance. Write documents, notes, reports
### The Paper Interface
```
┌────────────────┬────────────────────────────────────────────────┐
│ │ [B] [I] [U] H1 H2 • ― 🔗 📷 [AI ✨] │
│ 📄 Notes ├────────────────────────────────────────────────┤
│ ──────────── │ │
│ Meeting Notes │ Project Proposal │
│ Project Plan │ ════════════════ │
│ Ideas │ │
│ │ Introduction │
│ ──────────── │ ──────────── │
│ Quick Start │ │
│ [📄 Blank] │ This document outlines our proposal for │
│ [📋 Meeting] │ the upcoming project. We aim to... │
│ [✓ To-Do] │ │
│ [🔬 Research] │ | │
│ │ │
└────────────────┴────────────────────────────────────────────────┘
```
<img src="../assets/chapter-04/paper-interface.svg" alt="Paper Interface" style="max-width: 100%; height: auto;">
### Creating a Document
@ -620,28 +509,7 @@ Research is like having a research assistant. Search the web, your documents, an
### The Research Interface
```
┌────────────────┬────────────────────────────────────────────────┐
│ │ │
│ 🔍 Research │ ┌────────────────────────────────────────┐ │
│ │ │ What are the best practices for... │ │
│ ──────────── │ └────────────────────────────────────────┘ │
│ Focus: │ │
│ [🌐 All] │ AI Answer: │
│ [📚 Academic] │ ══════════ │
│ [💻 Code] │ Based on multiple sources, here are the │
│ [🏠 Internal] │ key best practices: │
│ │ │
│ Collections: │ 1. Start with clear requirements │
│ 📁 Project A │ 2. Use iterative development │
│ 📁 References │ 3. Test early and often │
│ │ │
│ Recent: │ Sources: │
│ • market size │ [1] industry-guide.com │
│ • competitors │ [2] techblog.dev │
│ │ [3] your-docs/guidelines.pdf │
└────────────────┴────────────────────────────────────────────────┘
```
<img src="../assets/chapter-04/research-interface.svg" alt="Research Interface" style="max-width: 100%; height: auto;">
### Search Modes
@ -692,26 +560,7 @@ Analytics shows you reports about usage, conversations, and performance. Underst
### The Analytics Interface
```
┌─────────────────────────────────────────────────────────────────┐
│ 📊 Analytics Dashboard [Last 24h ▼] [⟳ Refresh] │
├─────────────────────────────────────────────────────────────────┤
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 1,234 │ │ 89% │ │ 2.3s │ │ 45 │ │
│ │ Messages │ │ Success │ │ Avg Time │ │ Users │ │
│ │ +12% │ │ Rate │ │ Response │ │ Today │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Messages Over Time Top Questions │
│ ┌─────────────────────────┐ ┌─────────────────────────┐ │
│ │ ╭─╮ │ │ 1. How do I reset... │ │
│ │ ╭╯ ╰╮ ╭─╮ │ │ 2. What is the status...│ │
│ │ ╭╯ ╰────╯ ╰╮ │ │ 3. Where can I find... │ │
│ │ ─╯ ╰── │ │ 4. Help with login │ │
│ └─────────────────────────┘ └─────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
```
<img src="../assets/chapter-04/analytics-interface.svg" alt="Analytics Interface" style="max-width: 100%; height: auto;">
### Key Metrics
@ -750,29 +599,7 @@ Designer lets you create bot conversations visually - like VB6 form designer, bu
### The Designer Interface
```
┌──────────────┬──────────────────────────────────────┬──────────┐
│ Toolbox │ Canvas │Properties│
├──────────────┼──────────────────────────────────────┼──────────┤
│ │ │ │
│ 💬 TALK │ ┌─────────┐ │ Node: │
│ 👂 HEAR │ │💬 TALK │ │ TALK │
│ 📝 SET │ │"Hello!" │───┐ │ │
│ │ └─────────┘ │ │ Message: │
│ ───────── │ ▼ │ [Hello!] │
│ │ ┌─────────┐ ┌─────────┐ │ │
│ 🔀 IF │ │👂 HEAR │──▶│🔀 IF │ │ │
│ 🔄 FOR │ │ name │ │name="Jo"│ │ │
│ 🔃 SWITCH │ └─────────┘ └────┬────┘ │ │
│ │ ┌───┴───┐ │ │
│ ───────── │ Yes No │ │
│ │ │ │ │ │
│ 📞 CALL │ ┌────┴──┐ ┌──┴────┐ │ │
│ 📧 SEND │ │💬TALK │ │💬TALK │ │ │
│ 💾 SAVE │ │"Hi Jo"│ │"Hello"│ │ │
│ │ └───────┘ └───────┘ │ │
└──────────────┴──────────────────────────────────────┴──────────┘
```
<img src="../assets/chapter-04/designer-interface.svg" alt="Designer Interface" style="max-width: 100%; height: auto;">
### Building a Dialog
@ -809,27 +636,7 @@ Designer lets you create bot conversations visually - like VB6 form designer, bu
### Example: Simple Greeting Dialog
```
┌─────────────────┐
│ 💬 TALK │
│ "What's your │
│ name?" │
└────────┬────────┘
┌─────────────────┐
│ 👂 HEAR │
│ as: name │
│ type: STRING │
└────────┬────────┘
┌─────────────────┐
│ 💬 TALK │
│ "Nice to meet │
│ you, {name}!" │
└─────────────────┘
```
The Designer canvas shows flow diagrams like the one in the interface above. A simple greeting dialog flows from a TALK node ("What's your name?") to a HEAR node (capturing the name as a string variable) to another TALK node ("Nice to meet you, {name}!").
**Generated Code:**
```basic
@ -861,25 +668,7 @@ Sources is your library of prompts, templates, tools, and AI models. Find and us
### The Sources Interface
```
┌─────────────────────────────────────────────────────────────────┐
│ Sources 🔍 Search... │
├─────────────────────────────────────────────────────────────────┤
│ [Prompts] [Templates] [MCP Servers] [LLM Tools] [Models] │
├──────────────┬──────────────────────────────────────────────────┤
│ │ │
│ Categories │ ⭐ Featured │
│ ─────────── │ ┌────────────┐ ┌────────────┐ │
│ 📝 Writing │ │ Customer │ │ Sales │ │
│ 📊 Analysis │ │ Service │ │ Assistant │ │
│ 💼 Business │ │ ──────────│ │ ──────────│ │
│ 💻 Code │ │ Handle │ │ Qualify │ │
│ 🎨 Creative │ │ support │ │ leads and │ │
│ │ │ inquiries │ │ schedule │ │
│ │ │ [Use] │ │ [Use] │ │
│ │ └────────────┘ └────────────┘ │
└──────────────┴──────────────────────────────────────────────────┘
```
<img src="../assets/chapter-04/sources-interface.svg" alt="Sources Interface" style="max-width: 100%; height: auto;">
### Tabs Explained
@ -921,24 +710,7 @@ Sources is your library of prompts, templates, tools, and AI models. Find and us
### Compliance Scanner
Check your bot dialogs for security issues:
```
┌─────────────────────────────────────────────────────────────────┐
│ 🛡 Compliance Scanner [Scan] [Export] │
├─────────────────────────────────────────────────────────────────┤
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ 2 │ │ 5 │ │ 3 │ │ 1 │ │ 0 │ │
│ │🔴Crit│ │🟠High│ │🟡Med │ │🟢Low │ │Info│ │
│ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘ │
├─────────────────────────────────────────────────────────────────┤
│ Severity │ Issue │ File │ Action │
│ ───────────────────────────────────────────────────────────── │
│ 🔴 Critical│ Hardcoded password │ start.bas:15 │ [Fix] │
│ 🔴 Critical│ API key exposed │ api.bas:42 │ [Fix] │
│ 🟠 High │ SQL injection risk │ data.bas:28 │ [Review] │
└─────────────────────────────────────────────────────────────────┘
```
<img src="../assets/chapter-04/compliance-interface.svg" alt="Compliance Scanner Interface" style="max-width: 100%; height: auto;">
**What It Checks:**
- Hardcoded passwords

BIN
docs/src/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View file

@ -0,0 +1,852 @@
//! Certificate Pinning Module
//!
//! Provides certificate pinning functionality to prevent man-in-the-middle attacks
//! by validating server certificates against pre-configured SHA-256 fingerprints.
//!
//! # Overview
//!
//! Certificate pinning adds an additional layer of security beyond standard TLS
//! certificate validation. Even if an attacker obtains a valid certificate from
//! a trusted CA, the connection will be rejected if the certificate's fingerprint
//! doesn't match the pinned value.
//!
//! # Usage
//!
//! ```rust,ignore
//! use botserver::security::cert_pinning::{CertPinningConfig, CertPinningManager, PinnedCert};
//!
//! let mut config = CertPinningConfig::default();
//! config.add_pin(PinnedCert::new(
//! "api.example.com",
//! "sha256//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
//! ));
//!
//! let manager = CertPinningManager::new(config);
//! let client = manager.create_pinned_client("api.example.com")?;
//! ```
use anyhow::{anyhow, Context, Result};
use base64::{engine::general_purpose::STANDARD as BASE64, Engine};
use reqwest::{Certificate, Client, ClientBuilder};
use ring::digest::{digest, SHA256};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fs;
use std::path::{Path, PathBuf};
use std::sync::{Arc, RwLock};
use std::time::Duration;
use tracing::{debug, error, info, warn};
use x509_parser::prelude::*;
/// Configuration for certificate pinning
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CertPinningConfig {
/// Enable certificate pinning globally
pub enabled: bool,
/// Pinned certificates by hostname
pub pins: HashMap<String, Vec<PinnedCert>>,
/// Whether to fail if no pin is configured for a host
pub require_pins: bool,
/// Allow backup pins (multiple pins per host for rotation)
pub allow_backup_pins: bool,
/// Report-only mode (log violations but don't block)
pub report_only: bool,
/// Path to store/load pin configuration
pub config_path: Option<PathBuf>,
/// Pin validation cache TTL in seconds
pub cache_ttl_secs: u64,
}
impl Default for CertPinningConfig {
fn default() -> Self {
Self {
enabled: true,
pins: HashMap::new(),
require_pins: false,
allow_backup_pins: true,
report_only: false,
config_path: None,
cache_ttl_secs: 3600,
}
}
}
impl CertPinningConfig {
/// Create a new config with pinning enabled
pub fn new() -> Self {
Self::default()
}
/// Create a strict config that requires pins for all hosts
pub fn strict() -> Self {
Self {
enabled: true,
pins: HashMap::new(),
require_pins: true,
allow_backup_pins: true,
report_only: false,
config_path: None,
cache_ttl_secs: 3600,
}
}
/// Create a report-only config for testing
pub fn report_only() -> Self {
Self {
enabled: true,
pins: HashMap::new(),
require_pins: false,
allow_backup_pins: true,
report_only: true,
config_path: None,
cache_ttl_secs: 3600,
}
}
/// Add a pinned certificate
pub fn add_pin(&mut self, pin: PinnedCert) {
let hostname = pin.hostname.clone();
self.pins.entry(hostname).or_default().push(pin);
}
/// Add multiple pins for a hostname (primary + backups)
pub fn add_pins(&mut self, hostname: &str, pins: Vec<PinnedCert>) {
self.pins.insert(hostname.to_string(), pins);
}
/// Remove all pins for a hostname
pub fn remove_pins(&mut self, hostname: &str) {
self.pins.remove(hostname);
}
/// Get pins for a hostname
pub fn get_pins(&self, hostname: &str) -> Option<&Vec<PinnedCert>> {
self.pins.get(hostname)
}
/// Load configuration from file
pub fn load_from_file(path: &Path) -> Result<Self> {
let content = fs::read_to_string(path)
.with_context(|| format!("Failed to read pin config from {:?}", path))?;
let config: Self =
serde_json::from_str(&content).context("Failed to parse pin configuration")?;
info!("Loaded certificate pinning config from {:?}", path);
Ok(config)
}
/// Save configuration to file
pub fn save_to_file(&self, path: &Path) -> Result<()> {
let content =
serde_json::to_string_pretty(self).context("Failed to serialize pin configuration")?;
fs::write(path, content)
.with_context(|| format!("Failed to write pin config to {:?}", path))?;
info!("Saved certificate pinning config to {:?}", path);
Ok(())
}
}
/// A pinned certificate entry
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PinnedCert {
/// Hostname this pin applies to
pub hostname: String,
/// SHA-256 fingerprint of the certificate's Subject Public Key Info (SPKI)
/// Format: "sha256//BASE64_ENCODED_HASH"
pub fingerprint: String,
/// Optional human-readable description
pub description: Option<String>,
/// Whether this is a backup pin
pub is_backup: bool,
/// Expiration date (for pin rotation planning)
pub expires_at: Option<chrono::DateTime<chrono::Utc>>,
/// Pin type (leaf certificate, intermediate, or root)
pub pin_type: PinType,
}
impl PinnedCert {
/// Create a new pinned certificate entry
pub fn new(hostname: &str, fingerprint: &str) -> Self {
Self {
hostname: hostname.to_string(),
fingerprint: fingerprint.to_string(),
description: None,
is_backup: false,
expires_at: None,
pin_type: PinType::Leaf,
}
}
/// Create a backup pin
pub fn backup(hostname: &str, fingerprint: &str) -> Self {
Self {
hostname: hostname.to_string(),
fingerprint: fingerprint.to_string(),
description: Some("Backup pin for certificate rotation".to_string()),
is_backup: true,
expires_at: None,
pin_type: PinType::Leaf,
}
}
/// Set the pin type
pub fn with_type(mut self, pin_type: PinType) -> Self {
self.pin_type = pin_type;
self
}
/// Set description
pub fn with_description(mut self, desc: &str) -> Self {
self.description = Some(desc.to_string());
self
}
/// Set expiration
pub fn with_expiration(mut self, expires: chrono::DateTime<chrono::Utc>) -> Self {
self.expires_at = Some(expires);
self
}
/// Extract the raw hash bytes from the fingerprint
pub fn get_hash_bytes(&self) -> Result<Vec<u8>> {
let hash_str = self
.fingerprint
.strip_prefix("sha256//")
.ok_or_else(|| anyhow!("Invalid fingerprint format, expected 'sha256//BASE64'"))?;
BASE64
.decode(hash_str)
.context("Failed to decode base64 fingerprint")
}
/// Verify if a certificate matches this pin
pub fn verify(&self, cert_der: &[u8]) -> Result<bool> {
let expected_hash = self.get_hash_bytes()?;
let actual_hash = compute_spki_fingerprint(cert_der)?;
Ok(expected_hash == actual_hash)
}
}
/// Type of certificate being pinned
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum PinType {
/// Pin the leaf/end-entity certificate
Leaf,
/// Pin an intermediate CA certificate
Intermediate,
/// Pin the root CA certificate
Root,
}
impl Default for PinType {
fn default() -> Self {
Self::Leaf
}
}
/// Result of a pin validation
#[derive(Debug, Clone)]
pub struct PinValidationResult {
/// Whether the pin validation passed
pub valid: bool,
/// The hostname that was validated
pub hostname: String,
/// Which pin matched (if any)
pub matched_pin: Option<String>,
/// The actual fingerprint of the certificate
pub actual_fingerprint: String,
/// Error message if validation failed
pub error: Option<String>,
/// Whether this was a backup pin match
pub backup_match: bool,
}
impl PinValidationResult {
/// Create a successful validation result
pub fn success(hostname: &str, fingerprint: &str, backup: bool) -> Self {
Self {
valid: true,
hostname: hostname.to_string(),
matched_pin: Some(fingerprint.to_string()),
actual_fingerprint: fingerprint.to_string(),
error: None,
backup_match: backup,
}
}
/// Create a failed validation result
pub fn failure(hostname: &str, actual: &str, error: &str) -> Self {
Self {
valid: false,
hostname: hostname.to_string(),
matched_pin: None,
actual_fingerprint: actual.to_string(),
error: Some(error.to_string()),
backup_match: false,
}
}
}
/// Certificate Pinning Manager
pub struct CertPinningManager {
config: Arc<RwLock<CertPinningConfig>>,
validation_cache: Arc<RwLock<HashMap<String, (PinValidationResult, std::time::Instant)>>>,
}
impl CertPinningManager {
/// Create a new certificate pinning manager
pub fn new(config: CertPinningConfig) -> Self {
Self {
config: Arc::new(RwLock::new(config)),
validation_cache: Arc::new(RwLock::new(HashMap::new())),
}
}
/// Create with default configuration
pub fn default_manager() -> Self {
Self::new(CertPinningConfig::default())
}
/// Check if pinning is enabled
pub fn is_enabled(&self) -> bool {
self.config.read().unwrap().enabled
}
/// Add a pin dynamically
pub fn add_pin(&self, pin: PinnedCert) -> Result<()> {
let mut config = self
.config
.write()
.map_err(|_| anyhow!("Failed to acquire write lock"))?;
config.add_pin(pin);
Ok(())
}
/// Remove pins for a hostname
pub fn remove_pins(&self, hostname: &str) -> Result<()> {
let mut config = self
.config
.write()
.map_err(|_| anyhow!("Failed to acquire write lock"))?;
config.remove_pins(hostname);
// Clear cache for this hostname
let mut cache = self
.validation_cache
.write()
.map_err(|_| anyhow!("Failed to acquire cache lock"))?;
cache.remove(hostname);
Ok(())
}
/// Validate a certificate against pinned fingerprints
pub fn validate_certificate(
&self,
hostname: &str,
cert_der: &[u8],
) -> Result<PinValidationResult> {
let config = self
.config
.read()
.map_err(|_| anyhow!("Failed to acquire read lock"))?;
if !config.enabled {
return Ok(PinValidationResult::success(hostname, "disabled", false));
}
// Check cache first
if let Ok(cache) = self.validation_cache.read() {
if let Some((result, timestamp)) = cache.get(hostname) {
if timestamp.elapsed().as_secs() < config.cache_ttl_secs {
return Ok(result.clone());
}
}
}
// Compute actual fingerprint
let actual_hash = compute_spki_fingerprint(cert_der)?;
let actual_fingerprint = format!("sha256//{}", BASE64.encode(&actual_hash));
// Get pins for this hostname
let pins = match config.get_pins(hostname) {
Some(pins) => pins,
None => {
if config.require_pins {
let result = PinValidationResult::failure(
hostname,
&actual_fingerprint,
"No pins configured for hostname",
);
if config.report_only {
warn!(
"Certificate pinning violation (report-only): {} - {}",
hostname, "No pins configured"
);
return Ok(PinValidationResult::success(hostname, "report-only", false));
}
return Ok(result);
}
// No pins required, pass through
return Ok(PinValidationResult::success(
hostname,
"no-pins-required",
false,
));
}
};
// Check against all pins
for pin in pins {
match pin.verify(cert_der) {
Ok(true) => {
let result =
PinValidationResult::success(hostname, &pin.fingerprint, pin.is_backup);
if pin.is_backup {
warn!(
"Certificate matched backup pin for {}: {}",
hostname,
pin.description.as_deref().unwrap_or("backup")
);
}
// Update cache
if let Ok(mut cache) = self.validation_cache.write() {
cache.insert(
hostname.to_string(),
(result.clone(), std::time::Instant::now()),
);
}
return Ok(result);
}
Ok(false) => continue,
Err(e) => {
debug!("Pin verification error for {}: {}", hostname, e);
continue;
}
}
}
// No pin matched
let result = PinValidationResult::failure(
hostname,
&actual_fingerprint,
&format!(
"Certificate fingerprint {} does not match any pinned certificate",
actual_fingerprint
),
);
if config.report_only {
warn!(
"Certificate pinning violation (report-only): {} - actual fingerprint: {}",
hostname, actual_fingerprint
);
return Ok(PinValidationResult::success(hostname, "report-only", false));
}
error!(
"Certificate pinning failure for {}: fingerprint {} not in pin set",
hostname, actual_fingerprint
);
Ok(result)
}
/// Create an HTTP client with certificate pinning for a specific host
pub fn create_pinned_client(&self, hostname: &str) -> Result<Client> {
self.create_pinned_client_with_options(hostname, None, Duration::from_secs(30))
}
/// Create an HTTP client with certificate pinning and custom options
pub fn create_pinned_client_with_options(
&self,
hostname: &str,
ca_cert: Option<&Certificate>,
timeout: Duration,
) -> Result<Client> {
let config = self
.config
.read()
.map_err(|_| anyhow!("Failed to acquire read lock"))?;
let mut builder = ClientBuilder::new()
.timeout(timeout)
.connect_timeout(Duration::from_secs(10))
.use_rustls_tls()
.https_only(true)
.tls_built_in_root_certs(true);
// Add custom CA if provided
if let Some(cert) = ca_cert {
builder = builder.add_root_certificate(cert.clone());
}
// If pinning is enabled and we have pins, we need to use a custom verifier
// Note: reqwest doesn't directly support custom certificate verification,
// so we validate after connection or use a pre-flight check
if config.enabled && config.get_pins(hostname).is_some() {
debug!(
"Creating pinned client for {} with {} pins",
hostname,
config.get_pins(hostname).map(|p| p.len()).unwrap_or(0)
);
}
builder.build().context("Failed to build HTTP client")
}
/// Validate a certificate from a PEM file
pub fn validate_pem_file(
&self,
hostname: &str,
pem_path: &Path,
) -> Result<PinValidationResult> {
let pem_data = fs::read(pem_path)
.with_context(|| format!("Failed to read PEM file: {:?}", pem_path))?;
let der = pem_to_der(&pem_data)?;
self.validate_certificate(hostname, &der)
}
/// Generate a pin from a certificate file
pub fn generate_pin_from_file(hostname: &str, cert_path: &Path) -> Result<PinnedCert> {
let cert_data = fs::read(cert_path)
.with_context(|| format!("Failed to read certificate: {:?}", cert_path))?;
// Try PEM first, then DER
let der = if cert_data.starts_with(b"-----BEGIN") {
pem_to_der(&cert_data)?
} else {
cert_data
};
let fingerprint = compute_spki_fingerprint(&der)?;
let fingerprint_str = format!("sha256//{}", BASE64.encode(&fingerprint));
Ok(PinnedCert::new(hostname, &fingerprint_str))
}
/// Generate pins for all certificates in a directory
pub fn generate_pins_from_directory(
hostname: &str,
cert_dir: &Path,
) -> Result<Vec<PinnedCert>> {
let mut pins = Vec::new();
for entry in fs::read_dir(cert_dir)? {
let entry = entry?;
let path = entry.path();
if path.is_file() {
let ext = path.extension().and_then(|e| e.to_str()).unwrap_or("");
if matches!(ext, "crt" | "pem" | "cer" | "der") {
match Self::generate_pin_from_file(hostname, &path) {
Ok(pin) => {
info!("Generated pin from {:?}: {}", path, pin.fingerprint);
pins.push(pin);
}
Err(e) => {
warn!("Failed to generate pin from {:?}: {}", path, e);
}
}
}
}
}
Ok(pins)
}
/// Export current pins to a file
pub fn export_pins(&self, path: &Path) -> Result<()> {
let config = self
.config
.read()
.map_err(|_| anyhow!("Failed to acquire read lock"))?;
config.save_to_file(path)
}
/// Import pins from a file
pub fn import_pins(&self, path: &Path) -> Result<()> {
let imported = CertPinningConfig::load_from_file(path)?;
let mut config = self
.config
.write()
.map_err(|_| anyhow!("Failed to acquire write lock"))?;
for (hostname, pins) in imported.pins {
config.pins.insert(hostname, pins);
}
// Clear cache
if let Ok(mut cache) = self.validation_cache.write() {
cache.clear();
}
Ok(())
}
/// Get statistics about pinned certificates
pub fn get_stats(&self) -> Result<PinningStats> {
let config = self
.config
.read()
.map_err(|_| anyhow!("Failed to acquire read lock"))?;
let mut total_pins = 0;
let mut backup_pins = 0;
let mut expiring_soon = 0;
let now = chrono::Utc::now();
let soon = now + chrono::Duration::days(30);
for pins in config.pins.values() {
for pin in pins {
total_pins += 1;
if pin.is_backup {
backup_pins += 1;
}
if let Some(expires) = pin.expires_at {
if expires < soon {
expiring_soon += 1;
}
}
}
}
Ok(PinningStats {
enabled: config.enabled,
total_hosts: config.pins.len(),
total_pins,
backup_pins,
expiring_soon,
report_only: config.report_only,
})
}
}
/// Statistics about certificate pinning
#[derive(Debug, Clone, Serialize)]
pub struct PinningStats {
pub enabled: bool,
pub total_hosts: usize,
pub total_pins: usize,
pub backup_pins: usize,
pub expiring_soon: usize,
pub report_only: bool,
}
/// Compute SHA-256 fingerprint of a certificate's Subject Public Key Info (SPKI)
pub fn compute_spki_fingerprint(cert_der: &[u8]) -> Result<Vec<u8>> {
let (_, cert) = X509Certificate::from_der(cert_der)
.map_err(|e| anyhow!("Failed to parse X.509 certificate: {}", e))?;
// Get the raw SPKI bytes
let spki = cert.public_key().raw;
// Compute SHA-256 hash
let hash = digest(&SHA256, spki);
Ok(hash.as_ref().to_vec())
}
/// Compute SHA-256 fingerprint of the entire certificate (not just SPKI)
pub fn compute_cert_fingerprint(cert_der: &[u8]) -> Vec<u8> {
let hash = digest(&SHA256, cert_der);
hash.as_ref().to_vec()
}
/// Convert PEM-encoded certificate to DER
pub fn pem_to_der(pem_data: &[u8]) -> Result<Vec<u8>> {
let pem_str = std::str::from_utf8(pem_data).context("Invalid UTF-8 in PEM data")?;
// Find certificate block
let start_marker = "-----BEGIN CERTIFICATE-----";
let end_marker = "-----END CERTIFICATE-----";
let start = pem_str
.find(start_marker)
.ok_or_else(|| anyhow!("No certificate found in PEM data"))?;
let end = pem_str
.find(end_marker)
.ok_or_else(|| anyhow!("Invalid PEM: missing end marker"))?;
let base64_data = &pem_str[start + start_marker.len()..end];
let cleaned: String = base64_data.chars().filter(|c| !c.is_whitespace()).collect();
BASE64
.decode(&cleaned)
.context("Failed to decode base64 certificate data")
}
/// Format a fingerprint for display
pub fn format_fingerprint(hash: &[u8]) -> String {
hash.iter()
.map(|b| format!("{:02X}", b))
.collect::<Vec<_>>()
.join(":")
}
/// Parse a formatted fingerprint back to bytes
pub fn parse_fingerprint(formatted: &str) -> Result<Vec<u8>> {
// Handle "sha256//BASE64" format
if let Some(base64_part) = formatted.strip_prefix("sha256//") {
return BASE64
.decode(base64_part)
.context("Failed to decode base64 fingerprint");
}
// Handle colon-separated hex format
if formatted.contains(':') {
let bytes: Result<Vec<u8>, _> = formatted
.split(':')
.map(|hex| u8::from_str_radix(hex, 16))
.collect();
return bytes.context("Failed to parse hex fingerprint");
}
// Try plain hex
let bytes: Result<Vec<u8>, _> = (0..formatted.len())
.step_by(2)
.map(|i| u8::from_str_radix(&formatted[i..i + 2], 16))
.collect();
bytes.context("Failed to parse fingerprint")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_pinned_cert_creation() {
let pin = PinnedCert::new(
"api.example.com",
"sha256//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
);
assert_eq!(pin.hostname, "api.example.com");
assert!(!pin.is_backup);
assert_eq!(pin.pin_type, PinType::Leaf);
}
#[test]
fn test_backup_pin() {
let pin = PinnedCert::backup(
"api.example.com",
"sha256//BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=",
);
assert!(pin.is_backup);
assert!(pin.description.is_some());
}
#[test]
fn test_config_add_pin() {
let mut config = CertPinningConfig::default();
config.add_pin(PinnedCert::new(
"example.com",
"sha256//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
));
assert!(config.get_pins("example.com").is_some());
assert_eq!(config.get_pins("example.com").unwrap().len(), 1);
}
#[test]
fn test_format_fingerprint() {
let hash = vec![0xAB, 0xCD, 0xEF, 0x12];
let formatted = format_fingerprint(&hash);
assert_eq!(formatted, "AB:CD:EF:12");
}
#[test]
fn test_parse_fingerprint_hex() {
let result = parse_fingerprint("AB:CD:EF:12").unwrap();
assert_eq!(result, vec![0xAB, 0xCD, 0xEF, 0x12]);
}
#[test]
fn test_parse_fingerprint_base64() {
let original = vec![0xAB, 0xCD, 0xEF, 0x12];
let base64 = format!("sha256//{}", BASE64.encode(&original));
let result = parse_fingerprint(&base64).unwrap();
assert_eq!(result, original);
}
#[test]
fn test_pinning_stats() {
let mut config = CertPinningConfig::default();
config.add_pin(PinnedCert::new(
"host1.com",
"sha256//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
));
config.add_pin(PinnedCert::backup(
"host1.com",
"sha256//BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=",
));
config.add_pin(PinnedCert::new(
"host2.com",
"sha256//CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC=",
));
let manager = CertPinningManager::new(config);
let stats = manager.get_stats().unwrap();
assert!(stats.enabled);
assert_eq!(stats.total_hosts, 2);
assert_eq!(stats.total_pins, 3);
assert_eq!(stats.backup_pins, 1);
}
#[test]
fn test_pem_to_der() {
// Minimal test PEM (this is a mock, real certs would be longer)
let mock_pem = b"-----BEGIN CERTIFICATE-----
MIIB
-----END CERTIFICATE-----";
// Should fail gracefully with invalid base64
let result = pem_to_der(mock_pem);
// We expect this to fail because "MIIB" is incomplete base64
assert!(result.is_err() || result.unwrap().len() > 0);
}
#[test]
fn test_manager_disabled() {
let mut config = CertPinningConfig::default();
config.enabled = false;
let manager = CertPinningManager::new(config);
assert!(!manager.is_enabled());
}
}

View file

@ -11,6 +11,7 @@
pub mod antivirus;
pub mod ca;
pub mod cert_pinning;
pub mod integration;
pub mod mutual_tls;
pub mod tls;
@ -20,6 +21,10 @@ pub use antivirus::{
ThreatSeverity, ThreatStatus, Vulnerability,
};
pub use ca::{CaConfig, CaManager, CertificateRequest, CertificateResponse};
pub use cert_pinning::{
compute_spki_fingerprint, format_fingerprint, parse_fingerprint, CertPinningConfig,
CertPinningManager, PinType, PinValidationResult, PinnedCert, PinningStats,
};
pub use integration::{
create_https_client, get_tls_integration, init_tls_integration, to_secure_url, TlsIntegration,
};