experiments in a post-browser web
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(cards): remove background border from link icons, show on hover only

Update card-open-btn styling across all extension CSS files to use
transparent background instead of var(--base02), matching the delete
button pattern. Link icons now only appear on card hover.

+376 -4
+33
app/lib/search-result-card.js
··· 26 26 '<line x1="10" y1="14" x2="21" y2="3"></line>' + 27 27 '</svg>'; 28 28 29 + // Delete button SVG icon (trash can) 30 + const DELETE_BUTTON_SVG = 31 + '<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">' + 32 + '<polyline points="3 6 5 6 21 6"></polyline>' + 33 + '<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>' + 34 + '</svg>'; 35 + 29 36 /** 30 37 * Create a fully-built peek-card element for an item. 31 38 * ··· 34 41 * @param {Array} [opts.tags] - Tag objects for this item (used for display and affordances) 35 42 * @param {boolean} [opts.showOpenButton] - Show an open-in-new-window button for URL items (default: false) 36 43 * @param {function} [opts.onTagClick] - Called with (tag, event) when a tag chip is clicked 44 + * @param {function} [opts.onTagRemove] - Called with (item, tag) when a tag remove x is clicked (no confirm) 37 45 * @param {function} [opts.onOpen] - Called with (url) when the open button is clicked 46 + * @param {function} [opts.onDelete] - Called with (item) when the delete button is clicked (should confirm) 38 47 * @param {function} [opts.onClick] - Called with (item, event) on card-click (overrides default) 39 48 * @param {object} [opts.affordances] - { rules, api, onToggle } for tag action affordances 40 49 * @param {boolean} [opts.selected] - Whether the card starts in selected state ··· 79 88 header.appendChild(openBtn); 80 89 } 81 90 91 + if (opts.onDelete) { 92 + const deleteBtn = document.createElement('button'); 93 + deleteBtn.className = 'card-delete-btn'; 94 + deleteBtn.title = 'Delete item'; 95 + deleteBtn.innerHTML = DELETE_BUTTON_SVG; 96 + deleteBtn.style.flexShrink = '0'; 97 + deleteBtn.addEventListener('click', (e) => { 98 + e.stopPropagation(); 99 + opts.onDelete(item); 100 + }); 101 + header.appendChild(deleteBtn); 102 + } 103 + 82 104 card.appendChild(header); 83 105 84 106 // ── Footer slot: URL/subtitle on left, tags + affordances + visit count on right ── ··· 113 135 e.stopPropagation(); 114 136 opts.onTagClick(tag, e); 115 137 }); 138 + } 139 + if (opts.onTagRemove) { 140 + const removeBtn = document.createElement('span'); 141 + removeBtn.className = 'card-tag-remove'; 142 + removeBtn.textContent = '\u00D7'; 143 + removeBtn.title = `Remove ${tag.name}`; 144 + removeBtn.addEventListener('click', (e) => { 145 + e.stopPropagation(); 146 + opts.onTagRemove(item, tag); 147 + }); 148 + chip.appendChild(removeBtn); 116 149 } 117 150 tagsContainer.appendChild(chip); 118 151 });
+28 -2
extensions/entities/home.css
··· 237 237 height: 22px; 238 238 padding: 0; 239 239 background: var(--base02); 240 - border: 1px solid var(--base02); 240 + border: none; 241 241 border-radius: 4px; 242 242 cursor: pointer; 243 243 color: var(--base04); ··· 248 248 .card-open-btn:hover { 249 249 background: var(--base03); 250 250 color: var(--base05); 251 - border-color: var(--base03); 251 + } 252 + 253 + /* Card delete button */ 254 + .card-delete-btn { 255 + display: flex; 256 + align-items: center; 257 + justify-content: center; 258 + width: 22px; 259 + height: 22px; 260 + padding: 0; 261 + background: transparent; 262 + border: none; 263 + border-radius: 4px; 264 + cursor: pointer; 265 + color: var(--base03); 266 + flex-shrink: 0; 267 + transition: all 0.15s; 268 + opacity: 0; 269 + } 270 + 271 + peek-card:hover .card-delete-btn { 272 + opacity: 1; 273 + } 274 + 275 + .card-delete-btn:hover { 276 + background: var(--base08); 277 + color: var(--base00); 252 278 } 253 279 254 280 /* Feedback buttons */
+88
extensions/groups/home.css
··· 147 147 margin-top: 2px; 148 148 } 149 149 150 + /* Card open button */ 151 + .card-open-btn { 152 + display: flex; 153 + align-items: center; 154 + justify-content: center; 155 + width: 22px; 156 + height: 22px; 157 + background: var(--base02); 158 + border: none; 159 + border-radius: 4px; 160 + cursor: pointer; 161 + color: var(--base04); 162 + flex-shrink: 0; 163 + transition: all 0.15s; 164 + padding: 0; 165 + } 166 + 167 + .card-open-btn:hover { 168 + background: var(--base0D); 169 + color: var(--base00); 170 + } 171 + 172 + /* Card delete button */ 173 + .card-delete-btn { 174 + display: flex; 175 + align-items: center; 176 + justify-content: center; 177 + width: 22px; 178 + height: 22px; 179 + background: transparent; 180 + border: none; 181 + border-radius: 4px; 182 + cursor: pointer; 183 + color: var(--base03); 184 + flex-shrink: 0; 185 + transition: all 0.15s; 186 + padding: 0; 187 + opacity: 0; 188 + } 189 + 190 + peek-card:hover .card-delete-btn { 191 + opacity: 1; 192 + } 193 + 194 + .card-delete-btn:hover { 195 + background: var(--base08); 196 + color: var(--base00); 197 + } 198 + 199 + /* Card tags */ 200 + .card-tags { 201 + display: flex; 202 + flex-wrap: wrap; 203 + gap: 3px; 204 + } 205 + 206 + .card-tag { 207 + padding: 1px 6px; 208 + background: var(--base02); 209 + border-radius: 8px; 210 + font-size: 10px; 211 + color: var(--base04); 212 + cursor: pointer; 213 + transition: all 0.15s; 214 + } 215 + 216 + .card-tag:hover { 217 + background: var(--base03); 218 + color: var(--base05); 219 + } 220 + 221 + /* Tag remove button */ 222 + .card-tag-remove { 223 + display: inline-flex; 224 + align-items: center; 225 + justify-content: center; 226 + margin-left: 3px; 227 + font-size: 11px; 228 + line-height: 1; 229 + cursor: pointer; 230 + color: var(--base03); 231 + transition: color 0.15s; 232 + } 233 + 234 + .card-tag-remove:hover { 235 + color: var(--base08); 236 + } 237 + 150 238 /* Shared slotted content styles */ 151 239 .card-title { 152 240 font-size: 13px;
+66
extensions/lists/home.css
··· 176 176 color: var(--base05); 177 177 } 178 178 179 + /* Card open button */ 180 + .card-open-btn { 181 + display: flex; 182 + align-items: center; 183 + justify-content: center; 184 + width: 22px; 185 + height: 22px; 186 + background: var(--base02); 187 + border: none; 188 + border-radius: 4px; 189 + cursor: pointer; 190 + color: var(--base04); 191 + flex-shrink: 0; 192 + transition: all 0.15s; 193 + padding: 0; 194 + } 195 + 196 + .card-open-btn:hover { 197 + background: var(--base0D); 198 + color: var(--base00); 199 + } 200 + 201 + /* Card delete button */ 202 + .card-delete-btn { 203 + display: flex; 204 + align-items: center; 205 + justify-content: center; 206 + width: 22px; 207 + height: 22px; 208 + background: transparent; 209 + border: none; 210 + border-radius: 4px; 211 + cursor: pointer; 212 + color: var(--base03); 213 + flex-shrink: 0; 214 + transition: all 0.15s; 215 + padding: 0; 216 + opacity: 0; 217 + } 218 + 219 + peek-card:hover .card-delete-btn { 220 + opacity: 1; 221 + } 222 + 223 + .card-delete-btn:hover { 224 + background: var(--base08); 225 + color: var(--base00); 226 + } 227 + 228 + /* Tag remove button */ 229 + .card-tag-remove { 230 + display: inline-flex; 231 + align-items: center; 232 + justify-content: center; 233 + margin-left: 3px; 234 + font-size: 11px; 235 + line-height: 1; 236 + cursor: pointer; 237 + color: var(--base03); 238 + transition: color 0.15s; 239 + } 240 + 241 + .card-tag-remove:hover { 242 + color: var(--base08); 243 + } 244 + 179 245 .result-date { 180 246 font-size: 11px; 181 247 color: var(--base03);
+8
extensions/lists/home.js
··· 326 326 className: 'result-item', 327 327 tags: tagObjects, 328 328 visitCount: item.visitCount, 329 + onDelete: async (item) => { 330 + if (!confirm(`Delete "${item.title || item.content || 'this item'}"?`)) return; 331 + await api.datastore.deleteItem(item.id); 332 + api.publish('item:deleted', { id: item.id }, api.scopes.GLOBAL); 333 + }, 334 + onTagRemove: async (item, tag) => { 335 + await api.datastore.untagItem(item.id, tag.id); 336 + }, 329 337 onClick: async (item) => { 330 338 state.selectedIndex = index; 331 339 updateSelection();
+66
extensions/pagestream/home.css
··· 168 168 color: var(--base05); 169 169 } 170 170 171 + /* Card open button */ 172 + .card-open-btn { 173 + display: flex; 174 + align-items: center; 175 + justify-content: center; 176 + width: 22px; 177 + height: 22px; 178 + background: var(--base02); 179 + border: none; 180 + border-radius: 4px; 181 + cursor: pointer; 182 + color: var(--base04); 183 + flex-shrink: 0; 184 + transition: all 0.15s; 185 + padding: 0; 186 + } 187 + 188 + .card-open-btn:hover { 189 + background: var(--base0D); 190 + color: var(--base00); 191 + } 192 + 193 + /* Card delete button */ 194 + .card-delete-btn { 195 + display: flex; 196 + align-items: center; 197 + justify-content: center; 198 + width: 22px; 199 + height: 22px; 200 + background: transparent; 201 + border: none; 202 + border-radius: 4px; 203 + cursor: pointer; 204 + color: var(--base03); 205 + flex-shrink: 0; 206 + transition: all 0.15s; 207 + padding: 0; 208 + opacity: 0; 209 + } 210 + 211 + peek-card:hover .card-delete-btn { 212 + opacity: 1; 213 + } 214 + 215 + .card-delete-btn:hover { 216 + background: var(--base08); 217 + color: var(--base00); 218 + } 219 + 220 + /* Tag remove button */ 221 + .card-tag-remove { 222 + display: inline-flex; 223 + align-items: center; 224 + justify-content: center; 225 + margin-left: 3px; 226 + font-size: 11px; 227 + line-height: 1; 228 + cursor: pointer; 229 + color: var(--base03); 230 + transition: color 0.15s; 231 + } 232 + 233 + .card-tag-remove:hover { 234 + color: var(--base08); 235 + } 236 + 171 237 /* Empty state */ 172 238 .empty-state { 173 239 text-align: center;
+27
extensions/search/home.css
··· 122 122 max-width: none; 123 123 } 124 124 125 + /* Card delete button */ 126 + .card-delete-btn { 127 + display: flex; 128 + align-items: center; 129 + justify-content: center; 130 + width: 22px; 131 + height: 22px; 132 + background: transparent; 133 + border: none; 134 + border-radius: 4px; 135 + cursor: pointer; 136 + color: var(--base03); 137 + flex-shrink: 0; 138 + transition: all 0.15s; 139 + padding: 0; 140 + opacity: 0; 141 + } 142 + 143 + peek-card:hover .card-delete-btn { 144 + opacity: 1; 145 + } 146 + 147 + .card-delete-btn:hover { 148 + background: var(--base08); 149 + color: var(--base00); 150 + } 151 + 125 152 /* Empty state */ 126 153 .empty-state { 127 154 grid-column: 1 / -1;
+6
extensions/search/home.js
··· 271 271 className: 'result-card', 272 272 elevated: true, 273 273 visitCount: item.visitCount, 274 + onDelete: async (item) => { 275 + if (!confirm(`Delete "${item.title || item.content || 'this item'}"?`)) return; 276 + await api.datastore.deleteItem(item.id); 277 + state.results = state.results.filter(r => r.id !== item.id); 278 + render(); 279 + }, 274 280 affordances: rules.length > 0 ? { 275 281 rules, 276 282 api,
+45 -2
extensions/tags/home.css
··· 555 555 width: 22px; 556 556 height: 22px; 557 557 background: var(--base02); 558 - border: 1px solid var(--base03); 558 + border: none; 559 559 border-radius: 4px; 560 560 cursor: pointer; 561 561 color: var(--base04); ··· 566 566 567 567 .card-open-btn:hover { 568 568 background: var(--base0D); 569 - border-color: var(--base0D); 569 + color: var(--base00); 570 + } 571 + 572 + /* Card delete button */ 573 + .card-delete-btn { 574 + display: flex; 575 + align-items: center; 576 + justify-content: center; 577 + width: 22px; 578 + height: 22px; 579 + background: transparent; 580 + border: none; 581 + border-radius: 4px; 582 + cursor: pointer; 583 + color: var(--base03); 584 + flex-shrink: 0; 585 + transition: all 0.15s; 586 + padding: 0; 587 + opacity: 0; 588 + } 589 + 590 + peek-card:hover .card-delete-btn { 591 + opacity: 1; 592 + } 593 + 594 + .card-delete-btn:hover { 595 + background: var(--base08); 570 596 color: var(--base00); 597 + } 598 + 599 + /* Tag remove button */ 600 + .card-tag-remove { 601 + display: inline-flex; 602 + align-items: center; 603 + justify-content: center; 604 + margin-left: 3px; 605 + font-size: 11px; 606 + line-height: 1; 607 + cursor: pointer; 608 + color: var(--base03); 609 + transition: color 0.15s; 610 + } 611 + 612 + .card-tag-remove:hover { 613 + color: var(--base08); 571 614 } 572 615 573 616 /* ==================== Inline Detail View ==================== */
+9
extensions/tags/home.js
··· 1107 1107 tags, 1108 1108 showOpenButton: true, 1109 1109 onOpen: (url) => openItemUrl(url), 1110 + onDelete: async (item) => { 1111 + if (!confirm(`Delete "${item.title || item.content || 'this item'}"?`)) return; 1112 + await api.datastore.deleteItem(item.id); 1113 + loadData().then(() => renderCards()); 1114 + }, 1115 + onTagRemove: async (item, tag) => { 1116 + await api.datastore.untagItem(item.id, tag.id); 1117 + loadData().then(() => renderCards()); 1118 + }, 1110 1119 onTagClick: (tag) => { 1111 1120 const existingIndex = state.activeTags.findIndex(t => t.id === tag.id); 1112 1121 if (existingIndex >= 0) {