support open browser

This commit is contained in:
Julian Freeman
2026-04-16 14:20:52 -04:00
parent 0b46db0b43
commit 436797abfa
8 changed files with 282 additions and 23 deletions

View File

@@ -14,7 +14,10 @@ const {
extensionMonogram,
extensionProfilesExpanded,
extensionSortKey,
isOpeningProfile,
loading,
openProfileError,
openBrowserProfile,
profileSortKey,
scanBrowsers,
sectionCount,
@@ -109,6 +112,10 @@ const {
<div class="content-scroll-area">
<section v-if="activeSection === 'profiles'" class="content-section">
<div v-if="openProfileError" class="inline-error">
{{ openProfileError }}
</div>
<div class="sort-bar">
<SortDropdown
v-model="profileSortKey"
@@ -138,7 +145,21 @@ const {
<div class="profile-body">
<div class="profile-topline">
<h4>{{ profile.name }}</h4>
<span class="badge neutral">{{ profile.id }}</span>
<div class="profile-actions">
<button
class="card-action-button"
:disabled="isOpeningProfile(currentBrowser.browserId, profile.id)"
type="button"
@click="openBrowserProfile(currentBrowser.browserId, profile.id)"
>
{{
isOpeningProfile(currentBrowser.browserId, profile.id)
? "Opening..."
: "Open"
}}
</button>
<span class="badge neutral">{{ profile.id }}</span>
</div>
</div>
<p class="profile-email">{{ profile.email || "No email found" }}</p>
</div>

View File

@@ -14,6 +14,8 @@ import type {
export function useBrowserAssistant() {
const loading = ref(true);
const error = ref("");
const openProfileError = ref("");
const openingProfileKey = ref("");
const response = ref<ScanResponse>({ browsers: [] });
const selectedBrowserId = ref("");
const activeSection = ref<ActiveSection>("profiles");
@@ -81,6 +83,30 @@ export function useBrowserAssistant() {
}
}
async function openBrowserProfile(browserId: string, profileId: string) {
const profileKey = `${browserId}:${profileId}`;
openingProfileKey.value = profileKey;
openProfileError.value = "";
try {
await invoke("open_browser_profile", {
browserId,
profileId,
});
} catch (openError) {
openProfileError.value =
openError instanceof Error
? openError.message
: "Failed to open the selected browser profile.";
} finally {
openingProfileKey.value = "";
}
}
function isOpeningProfile(browserId: string, profileId: string) {
return openingProfileKey.value === `${browserId}:${profileId}`;
}
function browserMonogram(browserId: string) {
if (browserId === "chrome") return "CH";
if (browserId === "edge") return "ED";
@@ -144,6 +170,9 @@ export function useBrowserAssistant() {
extensionProfilesExpanded,
extensionSortKey,
loading,
isOpeningProfile,
openProfileError,
openBrowserProfile,
profileSortKey,
scanBrowsers,
sectionCount,

View File

@@ -289,6 +289,16 @@ button {
padding: 16px;
}
.inline-error {
margin-bottom: 12px;
padding: 10px 12px;
border: 1px solid rgba(239, 68, 68, 0.18);
border-radius: 12px;
background: rgba(254, 242, 242, 0.92);
color: #b42318;
font-size: 0.86rem;
}
.sort-bar {
display: flex;
justify-content: flex-end;
@@ -524,6 +534,12 @@ button {
line-height: 1.35;
}
.profile-actions {
display: inline-flex;
align-items: center;
gap: 8px;
}
.profile-email,
.meta-line,
.bookmark-url {
@@ -561,6 +577,36 @@ button {
cursor: pointer;
}
.card-action-button {
padding: 6px 10px;
border-radius: 10px;
background: linear-gradient(180deg, rgba(255, 255, 255, 0.96), rgba(241, 245, 249, 0.92));
border: 1px solid rgba(148, 163, 184, 0.24);
color: var(--text);
font-size: 0.8rem;
font-weight: 600;
cursor: pointer;
transition:
border-color 160ms ease,
background 160ms ease,
box-shadow 160ms ease;
}
.card-action-button:hover {
border-color: rgba(100, 116, 139, 0.36);
background: linear-gradient(180deg, rgba(255, 255, 255, 1), rgba(226, 232, 240, 0.9));
}
.card-action-button:disabled {
cursor: default;
opacity: 0.7;
border-color: rgba(148, 163, 184, 0.2);
}
.card-action-button:active {
box-shadow: inset 0 2px 4px rgba(148, 163, 184, 0.18);
}
.disclosure-panel {
display: flex;
flex-wrap: wrap;