|
2 | 2 | <html lang="en"> |
3 | 3 | <head> |
4 | 4 | <meta charset="UTF-8"> |
5 | | - <title>1-File CRM - OpenFDD</title> |
| 5 | + <title>Personal CRM - OpenFDD</title> |
6 | 6 | </head> |
7 | | -<body style="background: #f1f5f9; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0;"> |
| 7 | +<body style="background: #f1f5f9; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; font-family: sans-serif;"> |
8 | 8 | <fdd-container extension=".fdd"> |
9 | 9 | <script type="application/vc+json" id="fdd-data"> |
10 | 10 | { |
11 | | - "issuer": "user-self", |
12 | | - "credentialSubject": { "contactName": "Alice Smith", "company": "Tech Corp", "role": "VP Engineering" } |
| 11 | + "issuer": "did:web:sales.mycompany.com", |
| 12 | + "credentialSubject": { |
| 13 | + "title": "My Personal CRM Workspace", |
| 14 | + "lastUpdated": "2026-04-10" |
| 15 | + }, |
| 16 | + "proof": { "signature": "demo_sig" } |
13 | 17 | } |
14 | 18 | </script> |
15 | 19 | <script type="application/json" id="user-notes"> |
16 | | - { "followUp": "Schedule a demo for next Tuesday.", "lastContacted": "2026-04-10" } |
| 20 | + { |
| 21 | + "contacts": [ |
| 22 | + {"name": "Alice Johnson", "role": "VP Engineering", "company": "TechCorp", "email": "alice@techcorp.io", "notes": "Solid technical background. Discussed expanding their SaaS offering in Q2.", "archived": false}, |
| 23 | + {"name": "Bob Smith", "role": "CEO", "company": "StartupX", "email": "bob@startupx.com", "notes": "Passionate founder. Not ready for seed series until next year.", "archived": true} |
| 24 | + ], |
| 25 | + "globalScratchpad": "Need to follow up with Alice before Q3. Keep Bob archived for now." |
| 26 | + } |
17 | 27 | </script> |
18 | 28 | <template shadowrootmode="open" bind="#fdd-data, #user-notes"> |
19 | 29 | <style> |
20 | 30 | :host { |
21 | | - display: block; font-family: system-ui, sans-serif; width: 400px; background: white; |
22 | | - border-radius: 16px; padding: 2rem; box-shadow: 0 10px 15px -3px rgba(0,0,0,0.1); |
23 | | - } |
24 | | - .notes-area { |
25 | | - width: 100%; height: 120px; margin-top: 5px; box-sizing: border-box; border-radius: 8px; |
26 | | - border: 1px solid #cbd5e1; padding: 10px; font-family: system-ui; resize: none; |
| 31 | + display: flex; width: 1000px; height: 600px; background: white; |
| 32 | + border-radius: 12px; box-shadow: 0 10px 25px rgba(0,0,0,0.1); overflow: hidden; |
27 | 33 | } |
28 | | - .notes-area:focus { outline: 2px solid #3b82f6; border-color: transparent; } |
29 | | - .contact-info { border-bottom: 2px dashed #e2e8f0; padding-bottom: 1rem; margin-bottom: 1rem; } |
30 | | - h2 { margin: 0; color: #0f172a; font-size: 1.5rem; } |
31 | | - .role { color: #64748b; font-size: 1rem; margin-top: 5px; } |
| 34 | + .sidebar { width: 350px; background: #f8fafc; border-right: 1px solid #e2e8f0; display: flex; flex-direction: column; } |
| 35 | + .sidebar-header { padding: 20px; background: #0f172a; color: white; } |
| 36 | + .sidebar-header h2 { margin: 0 0 10px 0; font-size: 1.2rem; } |
| 37 | + .sidebar-content { flex: 1; overflow-y: auto; padding: 10px; } |
| 38 | + .search-bar { width: 100%; padding: 10px; border-radius: 6px; border: none; box-sizing: border-box; margin-bottom: 15px; } |
| 39 | + |
| 40 | + .contact-card { background: white; padding: 15px; border-radius: 8px; margin-bottom: 10px; border: 1px solid #cbd5e1; box-shadow: 0 2px 4px rgba(0,0,0,0.02); } |
| 41 | + .contact-card h3 { margin: 0 0 5px 0; color: #1e293b; font-size: 1.1rem; display: flex; justify-content: space-between; align-items: center;} |
| 42 | + .contact-card p { margin: 0 0 10px 0; color: #64748b; font-size: 0.9rem; } |
| 43 | + .actions { display: flex; gap: 8px; margin-top: 15px;} |
| 44 | + button { cursor: pointer; padding: 6px 12px; border-radius: 4px; border: none; font-weight: bold; font-size: 0.8rem; } |
| 45 | + .btn-archive { background: #fef3c7; color: #d97706; } |
| 46 | + .btn-delete { background: #fee2e2; color: #dc2626; } |
| 47 | + .btn-unarchive { background: #dbeafe; color: #2563eb; } |
| 48 | + .btn-edit { background: #3b82f6; color: white; } |
| 49 | + |
| 50 | + .main-panel { flex: 1; padding: 40px; background: #ffffff; overflow-y: auto; } |
| 51 | + .main-panel h2 { color: #0f172a; margin-top: 0; } |
| 52 | + |
| 53 | + form { display: flex; flex-direction: column; gap: 15px; max-width: 400px; margin-top: 20px; } |
| 54 | + input, textarea { padding: 10px; border: 1px solid #cbd5e1; border-radius: 6px; font-family: sans-serif; background: #fdfdfd;} |
| 55 | + textarea { resize: vertical; } |
| 56 | + .btn-submit { background: #10b981; color: white; padding: 12px; font-size: 1rem; } |
| 57 | + |
| 58 | + .archived-badge { display: inline-block; background: #cbd5e1; color: #334155; padding: 2px 6px; border-radius: 4px; font-size: 0.7rem; vertical-align: middle;} |
| 59 | + |
| 60 | + .field-group { display: flex; flex-direction: column; gap: 5px; margin-bottom: 15px; } |
| 61 | + .field-group label { font-size: 0.85rem; font-weight: bold; color: #64748b; text-transform: uppercase; letter-spacing: 0.5px;} |
32 | 62 | </style> |
33 | | - <div class="contact-info"> |
34 | | - <h2>{{contactName}}</h2> |
35 | | - <div class="role"><strong>{{role}}</strong> at {{company}}</div> |
36 | | - </div> |
37 | | - <div> |
38 | | - <label style="font-weight: bold; color: #475569; font-size: 0.9rem;">My Notes (Auto-saves to disk):</label> |
39 | | - <textarea name="user-notes.followUp" class="notes-area" autosave>{{followUp}}</textarea> |
| 63 | + |
| 64 | + <div class="sidebar"> |
| 65 | + <div class="sidebar-header"> |
| 66 | + <h2>{{title}}</h2> |
| 67 | + <input type="text" class="search-bar" placeholder="Search contacts..." data-filter-target=".contact-card" data-filter-attr="data-name"> |
| 68 | + </div> |
| 69 | + <div class="sidebar-content"> |
| 70 | + {{#each contacts}} |
| 71 | + <div class="contact-card" data-name="{{name}} {{company}}"> |
| 72 | + <h3> |
| 73 | + <span>{{name}} <span class="archived-badge" fdd-if="{{archived}}">ARCHIVED</span></span> |
| 74 | + <!-- EPHEMERAL STATE UI TARGETING --> |
| 75 | + <button class="btn-edit" fdd-action="set-ui" fdd-target="selectedContact" fdd-value="{{@index}}">Edit</button> |
| 76 | + </h3> |
| 77 | + <p>{{role}} @ {{company}}</p> |
| 78 | + |
| 79 | + <div class="actions"> |
| 80 | + <button class="btn-archive" fdd-unless="{{archived}}" fdd-action="set" fdd-target="user-notes.contacts.{{@index}}.archived" fdd-value="true">Archive</button> |
| 81 | + <button class="btn-unarchive" fdd-if="{{archived}}" fdd-action="set" fdd-target="user-notes.contacts.{{@index}}.archived" fdd-value="false">Restore</button> |
| 82 | + <button class="btn-delete" fdd-action="delete" fdd-target="user-notes.contacts" fdd-index="{{@index}}">Delete</button> |
| 83 | + </div> |
| 84 | + </div> |
| 85 | + {{/each}} |
| 86 | + </div> |
40 | 87 | </div> |
41 | | - <div style="margin-top:1rem; font-size:0.85rem; color:#94a3b8; display:flex; justify-content:space-between;"> |
42 | | - <span>Last Contacted: {{lastContacted}}</span> |
43 | | - <span style="color:#10b981; font-weight:bold;">1-File Sync Active</span> |
| 88 | + |
| 89 | + <div class="main-panel"> |
| 90 | + |
| 91 | + <!-- FALLBACK/EMPTY STATE -> VISIBLE WHEN selectedContact is 'undefined' --> |
| 92 | + <div fdd-match="ui.selectedContact" fdd-value="undefined"> |
| 93 | + <h2>Add New Contact</h2> |
| 94 | + <p style="color: #64748b;">This declarative form binds directly to your secure FDD Array via <code>fdd-push</code>. It requires zero JavaScript to execute!</p> |
| 95 | + |
| 96 | + <form fdd-action="push" fdd-target="user-notes.contacts"> |
| 97 | + <input type="text" name="name" placeholder="Full Name" required> |
| 98 | + <input type="text" name="role" placeholder="Job Title" required> |
| 99 | + <input type="text" name="company" placeholder="Company" required> |
| 100 | + <input type="email" name="email" placeholder="Email Address"> |
| 101 | + <input type="hidden" name="archived" value="false"> |
| 102 | + <button type="submit" class="btn-submit">+ Append to CRM</button> |
| 103 | + </form> |
| 104 | + |
| 105 | + <div style="margin-top: 50px;"> |
| 106 | + <h3 style="color: #0f172a; margin-bottom: 10px;">Workspace Notepad</h3> |
| 107 | + <textarea name="user-notes.globalScratchpad" autosave style="width: 100%; height: 100px;">{{globalScratchpad}}</textarea> |
| 108 | + </div> |
| 109 | + </div> |
| 110 | + |
| 111 | + <!-- DEEP VIEW / ACTIVE EDIT RECORD -> VISIBLE ONLY WHEN ui.selectedContact == @index --> |
| 112 | + {{#each contacts}} |
| 113 | + <div fdd-match="ui.selectedContact" fdd-value="{{@index}}"> |
| 114 | + <div style="display: flex; justify-content: space-between; align-items: center; border-bottom: 2px solid #e2e8f0; padding-bottom: 15px; margin-bottom: 25px;"> |
| 115 | + <h2 style="margin: 0; color: #2563eb;">Editing: {{name}}</h2> |
| 116 | + <!-- Closes the deep view by erasing the ephemeral UI state explicitly --> |
| 117 | + <button fdd-action="set-ui" fdd-target="selectedContact" fdd-value="undefined" style="background: transparent; border: 1px solid #cbd5e1; color: #475569;">Close View</button> |
| 118 | + </div> |
| 119 | + |
| 120 | + <div class="field-group"> |
| 121 | + <label>Full Name</label> |
| 122 | + <input name="user-notes.contacts.{{@index}}.name" value="{{name}}" autosave> |
| 123 | + </div> |
| 124 | + <div class="field-group"> |
| 125 | + <label>Professional Role</label> |
| 126 | + <input name="user-notes.contacts.{{@index}}.role" value="{{role}}" autosave> |
| 127 | + </div> |
| 128 | + <div class="field-group"> |
| 129 | + <label>Company</label> |
| 130 | + <input name="user-notes.contacts.{{@index}}.company" value="{{company}}" autosave> |
| 131 | + </div> |
| 132 | + <div class="field-group"> |
| 133 | + <label>Email Address</label> |
| 134 | + <input type="email" name="user-notes.contacts.{{@index}}.email" value="{{email}}" autosave> |
| 135 | + </div> |
| 136 | + <div class="field-group" style="margin-top: 15px;"> |
| 137 | + <label>Private Notes</label> |
| 138 | + <textarea name="user-notes.contacts.{{@index}}.notes" autosave style="height: 150px;">{{notes}}</textarea> |
| 139 | + </div> |
| 140 | + </div> |
| 141 | + {{/each}} |
| 142 | + |
44 | 143 | </div> |
45 | 144 | </template> |
46 | 145 | </fdd-container> |
|
0 commit comments