tighten ui

This commit is contained in:
Julian Freeman
2026-04-16 13:07:58 -04:00
parent c8a3d92be4
commit 3a180fc5db
2 changed files with 143 additions and 73 deletions

View File

@@ -50,6 +50,8 @@ const error = ref("");
const response = ref<ScanResponse>({ browsers: [] }); const response = ref<ScanResponse>({ browsers: [] });
const selectedBrowserId = ref(""); const selectedBrowserId = ref("");
const activeSection = ref<"profiles" | "extensions" | "bookmarks">("profiles"); const activeSection = ref<"profiles" | "extensions" | "bookmarks">("profiles");
const expandedExtensionIds = ref<string[]>([]);
const expandedBookmarkUrls = ref<string[]>([]);
const browsers = computed(() => response.value.browsers); const browsers = computed(() => response.value.browsers);
const currentBrowser = computed(() => const currentBrowser = computed(() =>
@@ -75,6 +77,11 @@ watch(
{ immediate: true }, { immediate: true },
); );
watch(selectedBrowserId, () => {
expandedExtensionIds.value = [];
expandedBookmarkUrls.value = [];
});
async function scanBrowsers() { async function scanBrowsers() {
loading.value = true; loading.value = true;
error.value = ""; error.value = "";
@@ -117,6 +124,26 @@ function sectionCount(section: "profiles" | "extensions" | "bookmarks") {
return currentBrowser.value.bookmarks.length; return currentBrowser.value.bookmarks.length;
} }
function toggleExtensionProfiles(extensionId: string) {
expandedExtensionIds.value = expandedExtensionIds.value.includes(extensionId)
? expandedExtensionIds.value.filter((id) => id !== extensionId)
: [...expandedExtensionIds.value, extensionId];
}
function toggleBookmarkProfiles(url: string) {
expandedBookmarkUrls.value = expandedBookmarkUrls.value.includes(url)
? expandedBookmarkUrls.value.filter((value) => value !== url)
: [...expandedBookmarkUrls.value, url];
}
function extensionProfilesExpanded(extensionId: string) {
return expandedExtensionIds.value.includes(extensionId);
}
function bookmarkProfilesExpanded(url: string) {
return expandedBookmarkUrls.value.includes(url);
}
onMounted(() => { onMounted(() => {
void scanBrowsers(); void scanBrowsers();
}); });
@@ -260,7 +287,6 @@ onMounted(() => {
<span class="badge neutral">{{ profile.id }}</span> <span class="badge neutral">{{ profile.id }}</span>
</div> </div>
<p class="profile-email">{{ profile.email || "No email found" }}</p> <p class="profile-email">{{ profile.email || "No email found" }}</p>
<p class="profile-path" :title="profile.path">{{ profile.path }}</p>
</div> </div>
</article> </article>
</div> </div>
@@ -300,7 +326,19 @@ onMounted(() => {
</span> </span>
</div> </div>
<p class="meta-line">{{ extension.id }}</p> <p class="meta-line">{{ extension.id }}</p>
<div class="badge-row"> <div class="source-disclosure">
<button
class="disclosure-button"
type="button"
@click="toggleExtensionProfiles(extension.id)"
>
<span>Profiles</span>
<span class="badge neutral">{{ extension.profileIds.length }}</span>
</button>
<div
v-if="extensionProfilesExpanded(extension.id)"
class="disclosure-panel"
>
<span <span
v-for="profileId in extension.profileIds" v-for="profileId in extension.profileIds"
:key="`${extension.id}-${profileId}`" :key="`${extension.id}-${profileId}`"
@@ -310,6 +348,7 @@ onMounted(() => {
</span> </span>
</div> </div>
</div> </div>
</div>
</article> </article>
</div> </div>
<div v-else class="empty-card"> <div v-else class="empty-card">
@@ -338,7 +377,19 @@ onMounted(() => {
<span class="badge neutral">{{ domainFromUrl(bookmark.url) }}</span> <span class="badge neutral">{{ domainFromUrl(bookmark.url) }}</span>
</div> </div>
<p class="bookmark-url" :title="bookmark.url">{{ bookmark.url }}</p> <p class="bookmark-url" :title="bookmark.url">{{ bookmark.url }}</p>
<div class="badge-row"> <div class="source-disclosure">
<button
class="disclosure-button"
type="button"
@click="toggleBookmarkProfiles(bookmark.url)"
>
<span>Profiles</span>
<span class="badge neutral">{{ bookmark.profileIds.length }}</span>
</button>
<div
v-if="bookmarkProfilesExpanded(bookmark.url)"
class="disclosure-panel"
>
<span <span
v-for="profileId in bookmark.profileIds" v-for="profileId in bookmark.profileIds"
:key="`${bookmark.url}-${profileId}`" :key="`${bookmark.url}-${profileId}`"
@@ -348,6 +399,7 @@ onMounted(() => {
</span> </span>
</div> </div>
</div> </div>
</div>
</article> </article>
</div> </div>
<div v-else class="empty-card"> <div v-else class="empty-card">

View File

@@ -61,8 +61,8 @@ button {
display: grid; display: grid;
grid-template-columns: 320px minmax(0, 1fr); grid-template-columns: 320px minmax(0, 1fr);
min-height: 100vh; min-height: 100vh;
padding: 24px; padding: 14px;
gap: 20px; gap: 14px;
} }
.sidebar, .sidebar,
@@ -74,10 +74,10 @@ button {
.sidebar { .sidebar {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 18px; gap: 14px;
padding: 28px 22px; padding: 20px 16px;
border: 1px solid var(--panel-border); border: 1px solid var(--panel-border);
border-radius: 28px; border-radius: 22px;
background: linear-gradient(180deg, rgba(255, 255, 255, 0.92), rgba(248, 250, 252, 0.7)); background: linear-gradient(180deg, rgba(255, 255, 255, 0.92), rgba(248, 250, 252, 0.7));
box-shadow: var(--shadow); box-shadow: var(--shadow);
} }
@@ -95,7 +95,7 @@ button {
} }
.sidebar-header h1 { .sidebar-header h1 {
font-size: 2rem; font-size: 1.72rem;
line-height: 1; line-height: 1;
} }
@@ -113,17 +113,17 @@ button {
} }
.eyebrow { .eyebrow {
margin: 0 0 8px; margin: 0 0 6px;
color: var(--muted-soft); color: var(--muted-soft);
font-size: 0.76rem; font-size: 0.72rem;
font-weight: 600; font-weight: 600;
letter-spacing: 0.18em; letter-spacing: 0.18em;
text-transform: uppercase; text-transform: uppercase;
} }
.refresh-button { .refresh-button {
padding: 13px 16px; padding: 11px 14px;
border-radius: 18px; border-radius: 15px;
background: linear-gradient(135deg, #10213f 0%, #213f75 100%); background: linear-gradient(135deg, #10213f 0%, #213f75 100%);
color: #fff; color: #fff;
cursor: pointer; cursor: pointer;
@@ -140,7 +140,7 @@ button {
.browser-nav { .browser-nav {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 12px; gap: 10px;
} }
.browser-nav-item { .browser-nav-item {
@@ -148,8 +148,8 @@ button {
align-items: center; align-items: center;
gap: 14px; gap: 14px;
width: 100%; width: 100%;
padding: 14px; padding: 11px;
border-radius: 20px; border-radius: 16px;
text-align: left; text-align: left;
cursor: pointer; cursor: pointer;
background: rgba(255, 255, 255, 0.54); background: rgba(255, 255, 255, 0.54);
@@ -192,11 +192,12 @@ button {
} }
.browser-nav-icon { .browser-nav-icon {
width: 50px; width: 42px;
height: 50px; height: 42px;
border-radius: 16px; border-radius: 13px;
color: #fff; color: #fff;
font-weight: 700; font-weight: 700;
font-size: 0.86rem;
letter-spacing: 0.08em; letter-spacing: 0.08em;
background: linear-gradient(135deg, #10213f, #365f9f); background: linear-gradient(135deg, #10213f, #365f9f);
} }
@@ -240,20 +241,20 @@ button {
.browser-nav-body span { .browser-nav-body span {
display: block; display: block;
margin-top: 4px; margin-top: 2px;
font-size: 0.88rem; font-size: 0.8rem;
line-height: 1.4; line-height: 1.4;
} }
.sidebar-empty { .sidebar-empty {
padding: 18px; padding: 14px;
border-radius: 18px; border-radius: 14px;
background: rgba(255, 255, 255, 0.58); background: rgba(255, 255, 255, 0.58);
border: 1px dashed rgba(148, 163, 184, 0.35); border: 1px dashed rgba(148, 163, 184, 0.35);
} }
.content-panel { .content-panel {
padding: 12px 6px 12px 0; padding: 4px 0 4px 0;
overflow: auto; overflow: auto;
} }
@@ -262,7 +263,7 @@ button {
.content-section, .content-section,
.state-panel { .state-panel {
border: 1px solid var(--panel-border); border: 1px solid var(--panel-border);
border-radius: 28px; border-radius: 22px;
background: var(--panel); background: var(--panel);
box-shadow: var(--shadow); box-shadow: var(--shadow);
} }
@@ -270,8 +271,8 @@ button {
.hero-card { .hero-card {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
gap: 24px; gap: 18px;
padding: 28px; padding: 20px;
background: background:
linear-gradient(135deg, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0.72)), linear-gradient(135deg, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0.72)),
linear-gradient(135deg, color-mix(in srgb, var(--accent) 16%, white), rgba(255, 255, 255, 0)); linear-gradient(135deg, color-mix(in srgb, var(--accent) 16%, white), rgba(255, 255, 255, 0));
@@ -285,13 +286,13 @@ button {
.hero-stats { .hero-stats {
display: grid; display: grid;
grid-template-columns: repeat(3, minmax(120px, 1fr)); grid-template-columns: repeat(3, minmax(120px, 1fr));
gap: 14px; gap: 10px;
width: min(460px, 100%); width: min(460px, 100%);
} }
.stat-card { .stat-card {
padding: 18px; padding: 14px;
border-radius: 22px; border-radius: 16px;
background: rgba(255, 255, 255, 0.72); background: rgba(255, 255, 255, 0.72);
border: 1px solid rgba(148, 163, 184, 0.18); border: 1px solid rgba(148, 163, 184, 0.18);
} }
@@ -299,25 +300,25 @@ button {
.stat-card span { .stat-card span {
display: block; display: block;
color: var(--muted-soft); color: var(--muted-soft);
font-size: 0.84rem; font-size: 0.78rem;
} }
.stat-card strong { .stat-card strong {
margin-top: 10px; margin-top: 6px;
font-size: 2rem; font-size: 1.7rem;
letter-spacing: -0.05em; letter-spacing: -0.05em;
} }
.content-section { .content-section {
margin-top: 20px; margin-top: 12px;
padding: 24px; padding: 18px;
} }
.section-tabs { .section-tabs {
display: flex; display: flex;
gap: 10px; gap: 10px;
margin-top: 20px; margin-top: 12px;
padding: 10px; padding: 8px;
} }
.section-tab { .section-tab {
@@ -327,8 +328,8 @@ button {
gap: 12px; gap: 12px;
min-width: 0; min-width: 0;
flex: 1; flex: 1;
padding: 14px 16px; padding: 10px 12px;
border-radius: 20px; border-radius: 15px;
color: var(--muted); color: var(--muted);
background: rgba(255, 255, 255, 0.58); background: rgba(255, 255, 255, 0.58);
cursor: pointer; cursor: pointer;
@@ -354,7 +355,7 @@ button {
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
gap: 16px; gap: 16px;
margin-bottom: 18px; margin-bottom: 12px;
} }
.count-pill, .count-pill,
@@ -371,7 +372,7 @@ button {
.count-pill { .count-pill {
min-width: 44px; min-width: 44px;
padding: 8px 12px; padding: 6px 10px;
} }
.badge { .badge {
@@ -387,15 +388,15 @@ button {
.bookmark-list { .bookmark-list {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 14px; gap: 10px;
} }
.profile-card, .profile-card,
.extension-card, .extension-card,
.bookmark-card, .bookmark-card,
.empty-card { .empty-card {
border-radius: 24px; border-radius: 18px;
padding: 18px; padding: 14px;
border: 1px solid rgba(148, 163, 184, 0.18); border: 1px solid rgba(148, 163, 184, 0.18);
background: var(--panel-strong); background: var(--panel-strong);
} }
@@ -404,13 +405,13 @@ button {
.extension-card, .extension-card,
.bookmark-card { .bookmark-card {
display: flex; display: flex;
gap: 16px; gap: 12px;
} }
.profile-avatar { .profile-avatar {
width: 64px; width: 52px;
height: 64px; height: 52px;
border-radius: 20px; border-radius: 15px;
background: linear-gradient(135deg, #dbeafe, #eff6ff); background: linear-gradient(135deg, #dbeafe, #eff6ff);
color: #1d4ed8; color: #1d4ed8;
font-size: 1.1rem; font-size: 1.1rem;
@@ -443,35 +444,52 @@ button {
.profile-topline h4, .profile-topline h4,
.extension-topline h4, .extension-topline h4,
.bookmark-topline h4 { .bookmark-topline h4 {
font-size: 1rem; font-size: 0.96rem;
line-height: 1.35; line-height: 1.35;
} }
.profile-email, .profile-email,
.profile-path,
.meta-line, .meta-line,
.bookmark-url { .bookmark-url {
margin-top: 8px; margin-top: 6px;
font-size: 0.92rem; font-size: 0.87rem;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }
.extension-icon { .extension-icon {
width: 56px; width: 46px;
height: 56px; height: 46px;
border-radius: 18px; border-radius: 14px;
background: linear-gradient(135deg, #e2e8f0, #f8fafc); background: linear-gradient(135deg, #e2e8f0, #f8fafc);
color: #475569; color: #475569;
font-weight: 700; font-weight: 700;
} }
.badge-row { .source-disclosure {
margin-top: 10px;
}
.disclosure-button {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
width: fit-content;
min-width: 120px;
padding: 7px 10px;
border-radius: 12px;
background: rgba(241, 245, 249, 0.9);
color: var(--badge-text);
cursor: pointer;
}
.disclosure-panel {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 8px; gap: 8px;
margin-top: 12px; margin-top: 8px;
} }
.state-panel, .state-panel,
@@ -483,7 +501,7 @@ button {
.state-panel { .state-panel {
min-height: 320px; min-height: 320px;
place-content: center; place-content: center;
padding: 36px; padding: 28px;
} }
.state-panel.error { .state-panel.error {
@@ -493,7 +511,7 @@ button {
@media (max-width: 1180px) { @media (max-width: 1180px) {
.app-shell { .app-shell {
grid-template-columns: 1fr; grid-template-columns: 1fr;
padding: 16px; padding: 12px;
} }
.content-panel { .content-panel {
@@ -523,7 +541,7 @@ button {
.profile-avatar, .profile-avatar,
.extension-icon { .extension-icon {
width: 56px; width: 50px;
height: 56px; height: 50px;
} }
} }