detailed profiles info

This commit is contained in:
Julian Freeman
2026-04-16 17:50:33 -04:00
parent 33f43aac56
commit 65b9401726
9 changed files with 356 additions and 98 deletions

View File

@@ -0,0 +1,188 @@
<script setup lang="ts">
import type {
AssociatedProfileSummary,
BookmarkAssociatedProfileSummary,
} from "../../types/browser";
type ModalProfile = AssociatedProfileSummary | BookmarkAssociatedProfileSummary;
defineProps<{
title: string;
profiles: ModalProfile[];
browserId: string;
isBookmark: boolean;
isOpeningProfile: (browserId: string, profileId: string) => boolean;
}>();
const emit = defineEmits<{
close: [];
openProfile: [browserId: string, profileId: string];
}>();
function hasBookmarkPath(
profile: ModalProfile,
): profile is BookmarkAssociatedProfileSummary {
return "bookmarkPath" in profile;
}
</script>
<template>
<div class="modal-backdrop" @click.self="emit('close')">
<section class="modal-card">
<div class="modal-header">
<h3>{{ title }}</h3>
<button class="secondary-button modal-close-button" type="button" @click="emit('close')">
Close
</button>
</div>
<div class="modal-list">
<article v-for="profile in profiles" :key="profile.id" class="modal-profile-card">
<div class="modal-profile-avatar">
<img
v-if="profile.avatarDataUrl"
:src="profile.avatarDataUrl"
:alt="`${profile.name} avatar`"
/>
<span v-else>{{ profile.avatarLabel }}</span>
</div>
<div class="modal-profile-body">
<div class="modal-profile-topline">
<div class="modal-profile-heading">
<h4>{{ profile.name }}</h4>
<span class="badge neutral">{{ profile.id }}</span>
</div>
<button
class="card-action-button"
type="button"
:disabled="isOpeningProfile(browserId, profile.id)"
@click="emit('openProfile', browserId, profile.id)"
>
{{ isOpeningProfile(browserId, profile.id) ? "Opening..." : "Open" }}
</button>
</div>
<p v-if="isBookmark && hasBookmarkPath(profile)" class="modal-bookmark-path">
{{ profile.bookmarkPath }}
</p>
</div>
</article>
</div>
</section>
</div>
</template>
<style scoped>
.modal-backdrop {
position: fixed;
inset: 0;
z-index: 40;
display: grid;
place-items: center;
padding: 24px;
background: rgba(15, 23, 42, 0.26);
backdrop-filter: blur(6px);
-webkit-backdrop-filter: blur(6px);
}
.modal-card {
width: min(720px, 100%);
max-height: min(78vh, 820px);
display: flex;
flex-direction: column;
gap: 14px;
padding: 16px;
border: 1px solid var(--panel-border);
border-radius: 22px;
background: rgba(255, 255, 255, 0.96);
box-shadow: 0 28px 70px rgba(15, 23, 42, 0.18);
}
.modal-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.modal-header h3,
.modal-profile-heading h4 {
margin: 0;
font-weight: 600;
letter-spacing: -0.03em;
}
.modal-list {
display: flex;
flex-direction: column;
gap: 10px;
min-height: 0;
overflow: auto;
padding-right: 4px;
}
.modal-profile-card {
display: flex;
gap: 12px;
padding: 12px;
border: 1px solid rgba(148, 163, 184, 0.18);
border-radius: 16px;
background: var(--panel-strong);
}
.modal-profile-avatar {
display: grid;
place-items: center;
flex-shrink: 0;
width: 46px;
height: 46px;
border-radius: 14px;
background: linear-gradient(135deg, #dbeafe, #eff6ff);
color: #1d4ed8;
font-size: 1rem;
font-weight: 700;
overflow: hidden;
}
.modal-profile-avatar img {
width: 100%;
height: 100%;
object-fit: cover;
}
.modal-profile-body {
min-width: 0;
flex: 1;
}
.modal-profile-topline {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 12px;
}
.modal-profile-heading {
display: flex;
align-items: center;
gap: 8px;
min-width: 0;
}
.modal-bookmark-path {
margin: 8px 0 0;
color: var(--muted);
font-size: 0.86rem;
}
@media (max-width: 720px) {
.modal-backdrop {
padding: 12px;
}
.modal-profile-card,
.modal-profile-topline,
.modal-profile-heading {
flex-direction: column;
}
}
</style>