Use full Trailhead Path Bookmarker name everywhere

- Popup header: tray icon + "Trailhead Path Bookmarker" title
- HTML <title>, electron-builder productName, and tray tooltip all match
- Popup width budget now also factors in the header's intrinsic width
  (icon + title + actions), so the brand never gets ellipsized — measured
  via h1 scrollWidth so overflow:hidden doesn't lie about content size
This commit is contained in:
David
2026-04-29 10:12:47 -04:00
parent 7150757671
commit 77c06d664b
4 changed files with 64 additions and 6 deletions
+1 -1
View File
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8" />
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self' http://localhost:5174 ws://localhost:5174" />
<title>Folder Bookmark Tray</title>
<title>Trailhead Path Bookmarker</title>
</head>
<body>
<div id="root"></div>
+1 -1
View File
@@ -29,7 +29,7 @@
},
"build": {
"appId": "com.dbeuttel.folder-bookmark-tray",
"productName": "Trailhead",
"productName": "Trailhead Path Bookmarker",
"files": [
"electron/**/*",
"dist/**/*",
+39 -4
View File
@@ -2,6 +2,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import Column from './Column.jsx';
import TabBar from './TabBar.jsx';
import ConfirmDialog from './ConfirmDialog.jsx';
import iconUrl from '../../assets/tray-icon.png';
const COLUMN_WIDTH = 216;
// Padding budget so the popup doesn't clip the tab strip: popup-inner has
@@ -41,11 +42,14 @@ export default function Popup({
const heightDebounceRef = useRef(null);
const settingsRef = useRef(null);
const tabStripRef = useRef(null);
const brandRef = useRef(null);
const actionsRef = useRef(null);
const [creatingColumn, setCreatingColumn] = useState(false);
const [draftColumnName, setDraftColumnName] = useState('');
const [settingsOpen, setSettingsOpen] = useState(false);
const [confirmRequest, setConfirmRequest] = useState(null);
const [tabStripScrollWidth, setTabStripScrollWidth] = useState(0);
const [headerMinWidth, setHeaderMinWidth] = useState(0);
const requestConfirm = useCallback((opts) => {
setConfirmRequest(opts);
@@ -86,6 +90,34 @@ export default function Popup({
};
}, []);
// Measure the popup header's intrinsic width so the brand never gets
// ellipsized. The h1 has overflow:hidden + text-overflow:ellipsis to keep
// it from forcing the popup wider than its content; we ask for that width
// explicitly through scrollWidth (which reports the full text width even
// when the element is clipped).
useEffect(() => {
if (!brandRef.current || !actionsRef.current) return undefined;
const update = () => {
const brand = brandRef.current;
const actions = actionsRef.current;
if (!brand || !actions) return;
const iconEl = brand.querySelector('img');
const titleEl = brand.querySelector('h1');
const iconW = iconEl ? iconEl.offsetWidth : 0;
const titleW = titleEl ? titleEl.scrollWidth : 0;
const brandW = iconW + (titleW > 0 ? 8 + titleW : 0);
const actionsW = actions.scrollWidth;
// 28px = popup-inner horizontal padding (14 each side); 8px = gap
// between brand and actions inside popup-header.
setHeaderMinWidth(brandW + 8 + actionsW + 28);
};
update();
const ro = new ResizeObserver(update);
ro.observe(brandRef.current);
ro.observe(actionsRef.current);
return () => ro.disconnect();
}, []);
// Watch the tab strip's scrollWidth so renames or new tabs widen the popup.
// ResizeObserver picks up both layout changes (window width changes) and
// content changes (a tab rename growing the strip).
@@ -112,8 +144,8 @@ export default function Popup({
useEffect(() => {
const colsWidth = Math.max(1, visibleColumns.length || 1) * COLUMN_WIDTH;
const tabsWidth = tabStripScrollWidth > 0 ? tabStripScrollWidth + TAB_STRIP_PADDING : 0;
window.bookmarks.setPopupWidth(Math.max(colsWidth, tabsWidth));
}, [visibleColumns.length, tabStripScrollWidth]);
window.bookmarks.setPopupWidth(Math.max(colsWidth, tabsWidth, headerMinWidth));
}, [visibleColumns.length, tabStripScrollWidth, headerMinWidth]);
const submitNewColumn = async () => {
const name = draftColumnName.trim();
@@ -152,8 +184,11 @@ export default function Popup({
<div className="popup">
<div className="popup-inner" ref={rootRef}>
<div className="popup-header drag-region">
<h1>Trailhead</h1>
<div className="header-actions">
<div className="popup-brand" ref={brandRef}>
<img src={iconUrl} alt="" className="popup-brand-icon" />
<h1>Trailhead Path Bookmarker</h1>
</div>
<div className="header-actions" ref={actionsRef}>
{!creatingColumn ? (
<button
className="icon-button"
+23
View File
@@ -173,6 +173,25 @@ html, body { height: 100%; }
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
min-width: 0;
}
.popup-brand {
display: flex;
align-items: center;
gap: 8px;
min-width: 0;
flex: 1;
}
.popup-brand-icon {
width: 18px;
height: 18px;
flex: 0 0 auto;
-webkit-user-drag: none;
user-select: none;
pointer-events: none;
}
.popup-header h1 {
@@ -180,6 +199,10 @@ html, body { height: 100%; }
font-weight: 600;
margin: 0;
letter-spacing: 0.2px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
min-width: 0;
}
.header-actions {